Published site at 27ed2ac071f0867df315a7e5d8acf49aabcd9399.
diff --git a/acid-semantics.html b/acid-semantics.html
index d5a9d53..a1c1266 100644
--- a/acid-semantics.html
+++ b/acid-semantics.html
@@ -450,7 +450,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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 6259d7f..998427d 100644
--- a/apache_hbase_reference_guide.pdf
+++ b/apache_hbase_reference_guide.pdf
Binary files differ
diff --git a/book.html b/book.html
index 83a1336..2f04cd9 100644
--- a/book.html
+++ b/book.html
@@ -42882,7 +42882,7 @@
 <div id="footer">
 <div id="footer-text">
 Version 3.0.0-SNAPSHOT<br>
-Last updated 2019-08-13 14:29:47 UTC
+Last updated 2019-08-14 14:29:43 UTC
 </div>
 </div>
 </body>
diff --git a/bulk-loads.html b/bulk-loads.html
index b6cfbcb..18a05ef 100644
--- a/bulk-loads.html
+++ b/bulk-loads.html
@@ -155,7 +155,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/checkstyle-aggregate.html b/checkstyle-aggregate.html
index 573186d..ca8aff9 100644
--- a/checkstyle-aggregate.html
+++ b/checkstyle-aggregate.html
@@ -58800,367 +58800,355 @@
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 109).</td>
-<td>1568</td></tr>
+<td>1571</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 101).</td>
-<td>1570</td></tr>
+<td>1573</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>MethodLength</td>
 <td>Method length is 180 lines (max allowed is 150).</td>
-<td>1578</td></tr>
+<td>1581</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 102).</td>
-<td>1619</td></tr>
+<td>1622</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>1809</td></tr>
+<td>1812</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>1816</td></tr>
+<td>1819</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>2035</td></tr>
+<td>2038</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>2051</td></tr>
+<td>2054</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>2113</td></tr>
+<td>2116</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>2281</td></tr>
+<td>2284</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>2304</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
 <td>2307</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>2354</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>2355</td></tr>
+<td>2310</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>2357</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>2358</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 101).</td>
-<td>2544</td></tr>
+<td>2547</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>coding</td>
 <td>InnerAssignment</td>
 <td>Inner assignments should be avoided.</td>
-<td>2652</td></tr>
+<td>2655</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>2724</td></tr>
+<td>2727</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>2743</td></tr>
+<td>2746</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>2765</td></tr>
+<td>2768</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>2797</td></tr>
+<td>2800</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>2941</td></tr>
+<td>2944</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'method def' child has incorrect indentation level 3, expected level should be 4.</td>
-<td>2956</td></tr>
+<td>2959</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>3006</td></tr>
+<td>3009</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>3046</td></tr>
+<td>3049</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>3058</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>3059</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>3060</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
 <td>3061</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'if' construct must use '{}'s.</td>
-<td>4156</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>4206</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>4303</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'if' construct must use '{}'s.</td>
-<td>4379</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>4389</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>4390</td></tr>
+<td>3062</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>3063</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>3064</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>4395</td></tr>
+<td>4159</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>4209</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>4306</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>4439</td></tr>
+<td>4382</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>4392</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>4393</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'if' construct must use '{}'s.</td>
+<td>4398</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'if' construct must use '{}'s.</td>
+<td>4442</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'if' has incorrect indentation level 3, expected level should be 4.</td>
-<td>4473</td></tr>
+<td>4476</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'if' child has incorrect indentation level 5, expected level should be 6.</td>
-<td>4474</td></tr>
+<td>4477</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>4553</td></tr>
+<td>4556</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>4555</td></tr>
+<td>4558</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>4616</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>4618</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
 <td>4619</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>4621</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>4622</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>4709</td></tr>
+<td>4712</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>MethodLength</td>
 <td>Method length is 195 lines (max allowed is 150).</td>
-<td>4761</td></tr>
+<td>4764</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'if' child has incorrect indentation level 9, expected level should be 8.</td>
-<td>4954</td></tr>
+<td>4957</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
-<td>5042</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
-<td>5043</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
-<td>5044</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
 <td>5045</td></tr>
-<tr class="b">
+<tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
 <td>5046</td></tr>
-<tr class="a">
+<tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
 <td>5047</td></tr>
-<tr class="b">
+<tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
 <td>5048</td></tr>
-<tr class="a">
+<tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
 <td>5049</td></tr>
-<tr class="b">
+<tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
 <td>5050</td></tr>
-<tr class="a">
+<tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
 <td>5051</td></tr>
-<tr class="b">
+<tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
 <td>5052</td></tr>
-<tr class="a">
+<tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
 <td>5053</td></tr>
-<tr class="b">
+<tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
 <td>5054</td></tr>
-<tr class="a">
+<tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
 <td>5055</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
+<td>5056</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
-<td>'method call' child has incorrect indentation level 10, expected level should be 12.</td>
-<td>5056</td></tr>
+<td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
+<td>5057</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
@@ -59169,196 +59157,196 @@
 <td>5058</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>5304</td></tr>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'method call' child has incorrect indentation level 10, expected level should be 12.</td>
+<td>5059</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>5305</td></tr>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
+<td>5061</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>5306</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
 <td>5307</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>5370</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>5810</td></tr>
+<td>5308</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>5899</td></tr>
+<td>5309</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>5310</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>5373</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>5813</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>5902</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>6137</td></tr>
+<td>6140</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6138</td></tr>
+<td>6141</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 114).</td>
-<td>6142</td></tr>
+<td>6145</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6158</td></tr>
+<td>6161</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6167</td></tr>
+<td>6170</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6175</td></tr>
+<td>6178</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6185</td></tr>
+<td>6188</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>6187</td></tr>
+<td>6190</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>MethodLength</td>
 <td>Method length is 193 lines (max allowed is 150).</td>
-<td>6192</td></tr>
+<td>6195</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'throws' has incorrect indentation level 4, expected level should be 6.</td>
-<td>6573</td></tr>
+<td>6576</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6651</td></tr>
+<td>6654</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6652</td></tr>
+<td>6655</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>6672</td></tr>
+<td>6675</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6692</td></tr>
+<td>6695</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6693</td></tr>
+<td>6696</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>MethodLength</td>
 <td>Method length is 221 lines (max allowed is 150).</td>
-<td>6712</td></tr>
+<td>6715</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 101).</td>
-<td>6767</td></tr>
+<td>6770</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>6924</td></tr>
+<td>6927</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>6938</td></tr>
+<td>6941</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>6944</td></tr>
+<td>6947</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6950</td></tr>
+<td>6953</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>6952</td></tr>
+<td>6955</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>coding</td>
 <td>InnerAssignment</td>
 <td>Inner assignments should be avoided.</td>
-<td>6995</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7080</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7082</td></tr>
+<td>6998</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
@@ -59370,385 +59358,385 @@
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7084</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
 <td>7085</td></tr>
-<tr class="a">
+<tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
 <td>7086</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7087</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7090</td></tr>
+<td>7088</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7089</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7093</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>7122</td></tr>
+<td>7125</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7127</td></tr>
+<td>7130</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7167</td></tr>
+<td>7170</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7168</td></tr>
+<td>7171</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7169</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
 <td>7172</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7177</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7186</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7187</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7188</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>7194</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7200</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7210</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7211</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7212</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
+<td>7175</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>7180</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7189</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7190</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7191</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>7197</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>7203</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7213</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7214</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
 <td>7215</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7219</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7229</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7230</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7231</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>NonEmptyAtclauseDescription</td>
-<td>At-clause should have a non-empty description.</td>
-<td>7236</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7242</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7261</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7262</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7263</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7280</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7281</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7282</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7303</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7304</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7305</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'if' construct must use '{}'s.</td>
-<td>7315</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7353</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'if' construct must use '{}'s.</td>
-<td>7413</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'if' construct must use '{}'s.</td>
-<td>7538</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7570</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>javadoc</td>
-<td>JavadocTagContinuationIndentation</td>
-<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7574</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>NonEmptyAtclauseDescription</td>
 <td>At-clause should have a non-empty description.</td>
-<td>7576</td></tr>
+<td>7218</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'if' construct must use '{}'s.</td>
-<td>7747</td></tr>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>7222</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7232</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7233</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7234</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>7239</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7767</td></tr>
+<td>7245</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7264</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7265</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7266</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7283</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7284</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7285</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7306</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7307</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7308</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'if' construct must use '{}'s.</td>
+<td>7318</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>7356</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'if' construct must use '{}'s.</td>
+<td>7416</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'if' construct must use '{}'s.</td>
+<td>7541</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7573</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>JavadocTagContinuationIndentation</td>
+<td>Line continuation have incorrect indentation level, expected level should be 2.</td>
+<td>7577</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>javadoc</td>
+<td>NonEmptyAtclauseDescription</td>
+<td>At-clause should have a non-empty description.</td>
+<td>7579</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'if' construct must use '{}'s.</td>
+<td>7750</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>7770</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 104).</td>
-<td>7805</td></tr>
+<td>7808</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>7909</td></tr>
+<td>7912</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
-<td>7934</td></tr>
+<td>7937</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>7992</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
 <td>7995</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'throws' has incorrect indentation level 2, expected level should be 4.</td>
+<td>7998</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>8016</td></tr>
+<td>8019</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>8064</td></tr>
+<td>8067</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 110).</td>
-<td>8103</td></tr>
+<td>8106</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 120).</td>
-<td>8104</td></tr>
+<td>8107</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 101).</td>
-<td>8109</td></tr>
+<td>8112</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>sizes</td>
 <td>LineLength</td>
 <td>Line is longer than 100 characters (found 106).</td>
-<td>8144</td></tr>
+<td>8147</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>javadoc</td>
 <td>JavadocTagContinuationIndentation</td>
 <td>Line continuation have incorrect indentation level, expected level should be 2.</td>
-<td>8267</td></tr>
+<td>8270</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'method def modifier' has incorrect indentation level 6, expected level should be one of the following: 8, 10.</td>
-<td>8335</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'if' has incorrect indentation level 8, expected level should be one of the following: 10, 12.</td>
-<td>8337</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'if' child has incorrect indentation level 10, expected level should be one of the following: 12, 14.</td>
 <td>8338</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
+<td>'if' has incorrect indentation level 8, expected level should be one of the following: 10, 12.</td>
+<td>8340</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'if' child has incorrect indentation level 10, expected level should be one of the following: 12, 14.</td>
+<td>8341</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
 <td>'if rcurly' has incorrect indentation level 8, expected level should be one of the following: 10, 12.</td>
-<td>8339</td></tr>
+<td>8342</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'method def rcurly' has incorrect indentation level 6, expected level should be one of the following: 8, 10.</td>
-<td>8340</td></tr>
+<td>8343</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'object def rcurly' has incorrect indentation level 4, expected level should be one of the following: 6, 8.</td>
-<td>8341</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'if' construct must use '{}'s.</td>
-<td>8507</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>blocks</td>
-<td>NeedBraces</td>
-<td>'else' construct must use '{}'s.</td>
-<td>8508</td></tr>
+<td>8344</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
@@ -59766,49 +59754,49 @@
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'if' construct must use '{}'s.</td>
-<td>8521</td></tr>
+<td>8513</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>blocks</td>
 <td>NeedBraces</td>
 <td>'else' construct must use '{}'s.</td>
-<td>8522</td></tr>
+<td>8514</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'if' construct must use '{}'s.</td>
+<td>8524</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>blocks</td>
+<td>NeedBraces</td>
+<td>'else' construct must use '{}'s.</td>
+<td>8525</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
-<td>8592</td></tr>
-<tr class="b">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'if' has incorrect indentation level 8, expected level should be 10.</td>
-<td>8594</td></tr>
-<tr class="a">
-<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
-<td>indentation</td>
-<td>Indentation</td>
-<td>'if' child has incorrect indentation level 10, expected level should be 12.</td>
 <td>8595</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
-<td>'if rcurly' has incorrect indentation level 8, expected level should be 10.</td>
-<td>8596</td></tr>
+<td>'if' has incorrect indentation level 8, expected level should be 10.</td>
+<td>8597</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
-<td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
-<td>8597</td></tr>
+<td>'if' child has incorrect indentation level 10, expected level should be 12.</td>
+<td>8598</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
-<td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
-<td>8598</td></tr>
+<td>'if rcurly' has incorrect indentation level 8, expected level should be 10.</td>
+<td>8599</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
@@ -59837,20 +59825,32 @@
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
-<td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
-<td>8607</td></tr>
+<td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
+<td>8606</td></tr>
 <tr class="b">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
+<td>8607</td></tr>
+<tr class="a">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
 <td>8610</td></tr>
+<tr class="b">
+<td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
+<td>indentation</td>
+<td>Indentation</td>
+<td>'case' child has incorrect indentation level 6, expected level should be 8.</td>
+<td>8613</td></tr>
 <tr class="a">
 <td><img src="images/icon_error_sml.gif" alt="" />&#160;Error</td>
 <td>indentation</td>
 <td>Indentation</td>
 <td>'block' child has incorrect indentation level 8, expected level should be 10.</td>
-<td>8611</td></tr></table></div>
+<td>8614</td></tr></table></div>
 <div class="section">
 <h3 id="org.apache.hadoop.hbase.regionserver.HRegionFileSystem.java">org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java</h3>
 <table border="0" class="table table-striped">
@@ -93183,7 +93183,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/coc.html b/coc.html
index 1114a3e..01a3c53 100644
--- a/coc.html
+++ b/coc.html
@@ -224,7 +224,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/dependencies.html b/dependencies.html
index 45f43f3..92c36b2 100644
--- a/dependencies.html
+++ b/dependencies.html
@@ -296,7 +296,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/dependency-convergence.html b/dependency-convergence.html
index 36ed242..177f677 100644
--- a/dependency-convergence.html
+++ b/dependency-convergence.html
@@ -679,7 +679,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/dependency-info.html b/dependency-info.html
index aa9b383..5fd536e 100644
--- a/dependency-info.html
+++ b/dependency-info.html
@@ -177,7 +177,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/dependency-management.html b/dependency-management.html
index 70097bf..ff27b51 100644
--- a/dependency-management.html
+++ b/dependency-management.html
@@ -893,7 +893,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/devapidocs/constant-values.html b/devapidocs/constant-values.html
index 6f6ac2b..8c6b8d1 100644
--- a/devapidocs/constant-values.html
+++ b/devapidocs/constant-values.html
@@ -3955,14 +3955,14 @@
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a></code></td>
 <td><code><a href="org/apache/hadoop/hbase/Version.html#date">date</a></code></td>
-<td class="colLast"><code>"Tue Aug 13 14:35:01 UTC 2019"</code></td>
+<td class="colLast"><code>"Wed Aug 14 14:35:17 UTC 2019"</code></td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><a name="org.apache.hadoop.hbase.Version.revision">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a></code></td>
 <td><code><a href="org/apache/hadoop/hbase/Version.html#revision">revision</a></code></td>
-<td class="colLast"><code>"8c1edb3bba56677b0ee106f340d12b42e999cdaa"</code></td>
+<td class="colLast"><code>"27ed2ac071f0867df315a7e5d8acf49aabcd9399"</code></td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><a name="org.apache.hadoop.hbase.Version.srcChecksum">
diff --git a/devapidocs/org/apache/hadoop/hbase/MetaTableAccessor.html b/devapidocs/org/apache/hadoop/hbase/MetaTableAccessor.html
index 3c3a943..ea38cf9 100644
--- a/devapidocs/org/apache/hadoop/hbase/MetaTableAccessor.html
+++ b/devapidocs/org/apache/hadoop/hbase/MetaTableAccessor.html
@@ -823,7 +823,7 @@
 </td>
 </tr>
 <tr id="i83" class="rowColor">
-<td class="colFirst"><code>private static <a href="../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a></code></td>
+<td class="colFirst"><code>static <a href="../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a></code></td>
 <td class="colLast"><code><span class="memberNameLink"><a href="../../../../org/apache/hadoop/hbase/MetaTableAccessor.html#makePutFromTableState-org.apache.hadoop.hbase.client.TableState-long-">makePutFromTableState</a></span>(<a href="../../../../org/apache/hadoop/hbase/client/TableState.html" title="class in org.apache.hadoop.hbase.client">TableState</a>&nbsp;state,
                      long&nbsp;ts)</code>
 <div class="block">Construct PUT for given state</div>
@@ -2640,8 +2640,8 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>makePutFromTableState</h4>
-<pre>private static&nbsp;<a href="../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;<a href="../../../../src-html/org/apache/hadoop/hbase/MetaTableAccessor.html#line.1658">makePutFromTableState</a>(<a href="../../../../org/apache/hadoop/hbase/client/TableState.html" title="class in org.apache.hadoop.hbase.client">TableState</a>&nbsp;state,
-                                         long&nbsp;ts)</pre>
+<pre>public static&nbsp;<a href="../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;<a href="../../../../src-html/org/apache/hadoop/hbase/MetaTableAccessor.html#line.1658">makePutFromTableState</a>(<a href="../../../../org/apache/hadoop/hbase/client/TableState.html" title="class in org.apache.hadoop.hbase.client">TableState</a>&nbsp;state,
+                                        long&nbsp;ts)</pre>
 <div class="block">Construct PUT for given state</div>
 <dl>
 <dt><span class="paramLabel">Parameters:</span></dt>
diff --git a/devapidocs/org/apache/hadoop/hbase/client/class-use/Put.html b/devapidocs/org/apache/hadoop/hbase/client/class-use/Put.html
index 2fa494e..6a1aca2 100644
--- a/devapidocs/org/apache/hadoop/hbase/client/class-use/Put.html
+++ b/devapidocs/org/apache/hadoop/hbase/client/class-use/Put.html
@@ -223,7 +223,7 @@
 </td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><code>private static <a href="../../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a></code></td>
+<td class="colFirst"><code>static <a href="../../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a></code></td>
 <td class="colLast"><span class="typeNameLabel">MetaTableAccessor.</span><code><span class="memberNameLink"><a href="../../../../../../org/apache/hadoop/hbase/MetaTableAccessor.html#makePutFromTableState-org.apache.hadoop.hbase.client.TableState-long-">makePutFromTableState</a></span>(<a href="../../../../../../org/apache/hadoop/hbase/client/TableState.html" title="class in org.apache.hadoop.hbase.client">TableState</a>&nbsp;state,
                      long&nbsp;ts)</code>
 <div class="block">Construct PUT for given state</div>
diff --git a/devapidocs/org/apache/hadoop/hbase/client/class-use/TableState.html b/devapidocs/org/apache/hadoop/hbase/client/class-use/TableState.html
index e177153..a9ac5b5 100644
--- a/devapidocs/org/apache/hadoop/hbase/client/class-use/TableState.html
+++ b/devapidocs/org/apache/hadoop/hbase/client/class-use/TableState.html
@@ -163,7 +163,7 @@
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colFirst"><code>private static <a href="../../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a></code></td>
+<td class="colFirst"><code>static <a href="../../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a></code></td>
 <td class="colLast"><span class="typeNameLabel">MetaTableAccessor.</span><code><span class="memberNameLink"><a href="../../../../../../org/apache/hadoop/hbase/MetaTableAccessor.html#makePutFromTableState-org.apache.hadoop.hbase.client.TableState-long-">makePutFromTableState</a></span>(<a href="../../../../../../org/apache/hadoop/hbase/client/TableState.html" title="class in org.apache.hadoop.hbase.client">TableState</a>&nbsp;state,
                      long&nbsp;ts)</code>
 <div class="block">Construct PUT for given state</div>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html
index 427c630..f8fbf98 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html
@@ -110,7 +110,7 @@
 <hr>
 <br>
 <pre><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html?is-external=true" title="class or interface in java.lang">@FunctionalInterface</a>
-public static interface <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3176">HRegion.BatchOperation.Visitor</a></pre>
+public static interface <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3179">HRegion.BatchOperation.Visitor</a></pre>
 <div class="block">Visitor interface for batch operations</div>
 </li>
 </ul>
@@ -155,7 +155,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>visit</h4>
-<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html#line.3181">visit</a>(int&nbsp;index)
+<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html#line.3184">visit</a>(int&nbsp;index)
        throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="paramLabel">Parameters:</span></dt>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html
index 217c37f..5c84859 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html
@@ -117,7 +117,7 @@
 </dl>
 <hr>
 <br>
-<pre>private abstract static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3146">HRegion.BatchOperation</a>&lt;T&gt;
+<pre>private abstract static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3149">HRegion.BatchOperation</a>&lt;T&gt;
 extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></pre>
 <div class="block">Class that tracks the progress of a batch operations, accumulating status codes and tracking
  the index at which processing is proceeding. These batch operations may get split into
@@ -408,7 +408,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>operations</h4>
-<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="type parameter in HRegion.BatchOperation">T</a>[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3147">operations</a></pre>
+<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="type parameter in HRegion.BatchOperation">T</a>[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3150">operations</a></pre>
 </li>
 </ul>
 <a name="retCodeDetails">
@@ -417,7 +417,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>retCodeDetails</h4>
-<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3148">retCodeDetails</a></pre>
+<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3151">retCodeDetails</a></pre>
 </li>
 </ul>
 <a name="walEditsFromCoprocessors">
@@ -426,7 +426,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>walEditsFromCoprocessors</h4>
-<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3149">walEditsFromCoprocessors</a></pre>
+<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3152">walEditsFromCoprocessors</a></pre>
 </li>
 </ul>
 <a name="familyCellMaps">
@@ -435,7 +435,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>familyCellMaps</h4>
-<pre>protected final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3151">familyCellMaps</a></pre>
+<pre>protected final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3154">familyCellMaps</a></pre>
 </li>
 </ul>
 <a name="region">
@@ -444,7 +444,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>region</h4>
-<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3153">region</a></pre>
+<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3156">region</a></pre>
 </li>
 </ul>
 <a name="nextIndexToProcess">
@@ -453,7 +453,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>nextIndexToProcess</h4>
-<pre>protected&nbsp;int <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3154">nextIndexToProcess</a></pre>
+<pre>protected&nbsp;int <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3157">nextIndexToProcess</a></pre>
 </li>
 </ul>
 <a name="observedExceptions">
@@ -462,7 +462,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>observedExceptions</h4>
-<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.ObservedExceptionsInBatch.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.ObservedExceptionsInBatch</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3155">observedExceptions</a></pre>
+<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.ObservedExceptionsInBatch.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.ObservedExceptionsInBatch</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3158">observedExceptions</a></pre>
 </li>
 </ul>
 <a name="durability">
@@ -471,7 +471,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>durability</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3157">durability</a></pre>
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3160">durability</a></pre>
 </li>
 </ul>
 <a name="atomic">
@@ -480,7 +480,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>atomic</h4>
-<pre>protected&nbsp;boolean <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3158">atomic</a></pre>
+<pre>protected&nbsp;boolean <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3161">atomic</a></pre>
 </li>
 </ul>
 </li>
@@ -499,7 +499,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>BatchOperation</h4>
-<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3160">BatchOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
+<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3163">BatchOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
                       <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="type parameter in HRegion.BatchOperation">T</a>[]&nbsp;operations)</pre>
 </li>
 </ul>
@@ -517,7 +517,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>visitBatchOperations</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3187">visitBatchOperations</a>(boolean&nbsp;pendingOnly,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3190">visitBatchOperations</a>(boolean&nbsp;pendingOnly,
                                  int&nbsp;lastIndexExclusive,
                                  <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html" title="interface in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation.Visitor</a>&nbsp;visitor)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -534,7 +534,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMutation</h4>
-<pre>public abstract&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3199">getMutation</a>(int&nbsp;index)</pre>
+<pre>public abstract&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3202">getMutation</a>(int&nbsp;index)</pre>
 </li>
 </ul>
 <a name="getNonceGroup-int-">
@@ -543,7 +543,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getNonceGroup</h4>
-<pre>public abstract&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3201">getNonceGroup</a>(int&nbsp;index)</pre>
+<pre>public abstract&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3204">getNonceGroup</a>(int&nbsp;index)</pre>
 </li>
 </ul>
 <a name="getNonce-int-">
@@ -552,7 +552,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getNonce</h4>
-<pre>public abstract&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3203">getNonce</a>(int&nbsp;index)</pre>
+<pre>public abstract&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3206">getNonce</a>(int&nbsp;index)</pre>
 </li>
 </ul>
 <a name="getMutationsForCoprocs--">
@@ -561,7 +561,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMutationsForCoprocs</h4>
-<pre>public abstract&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3208">getMutationsForCoprocs</a>()</pre>
+<pre>public abstract&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3211">getMutationsForCoprocs</a>()</pre>
 <div class="block">This method is potentially expensive and useful mostly for non-replay CP path.</div>
 </li>
 </ul>
@@ -571,7 +571,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isInReplay</h4>
-<pre>public abstract&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3210">isInReplay</a>()</pre>
+<pre>public abstract&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3213">isInReplay</a>()</pre>
 </li>
 </ul>
 <a name="getOrigLogSeqNum--">
@@ -580,7 +580,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOrigLogSeqNum</h4>
-<pre>public abstract&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3212">getOrigLogSeqNum</a>()</pre>
+<pre>public abstract&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3215">getOrigLogSeqNum</a>()</pre>
 </li>
 </ul>
 <a name="startRegionOperation--">
@@ -589,7 +589,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>startRegionOperation</h4>
-<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3214">startRegionOperation</a>()
+<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3217">startRegionOperation</a>()
                                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -603,7 +603,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>closeRegionOperation</h4>
-<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3216">closeRegionOperation</a>()
+<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3219">closeRegionOperation</a>()
                                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -617,7 +617,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPrepare</h4>
-<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3225">checkAndPrepare</a>()
+<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3228">checkAndPrepare</a>()
                               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs
  CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on
@@ -636,7 +636,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPreparePut</h4>
-<pre>protected abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3231">checkAndPreparePut</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;p)
+<pre>protected abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3234">checkAndPreparePut</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;p)
                                     throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Implement any Put request specific check and prepare logic here. Please refer to
  <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#checkAndPrepareMutation-org.apache.hadoop.hbase.client.Mutation-long-"><code>checkAndPrepareMutation(Mutation, long)</code></a> for how its used.</div>
@@ -652,7 +652,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>prepareMiniBatchOperations</h4>
-<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3237">prepareMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public abstract&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3240">prepareMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                                 long&nbsp;timestamp,
                                                 <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;acquiredRowLocks)
                                          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -670,7 +670,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>writeMiniBatchOperationsToMemStore</h4>
-<pre>public abstract&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3243">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public abstract&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3246">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                                                                              <a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;writeEntry)
                                                                                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Write mini-batch operations to MemStore</div>
@@ -686,7 +686,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>writeMiniBatchOperationsToMemStore</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3247">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3250">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                                   long&nbsp;writeNumber)
                                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -701,7 +701,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isDone</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3267">isDone</a>()</pre>
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3270">isDone</a>()</pre>
 </li>
 </ul>
 <a name="size--">
@@ -710,7 +710,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>size</h4>
-<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3271">size</a>()</pre>
+<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3274">size</a>()</pre>
 </li>
 </ul>
 <a name="isOperationPending-int-">
@@ -719,7 +719,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isOperationPending</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3275">isOperationPending</a>(int&nbsp;index)</pre>
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3278">isOperationPending</a>(int&nbsp;index)</pre>
 </li>
 </ul>
 <a name="getClusterIds--">
@@ -728,7 +728,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getClusterIds</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html?is-external=true" title="class or interface in java.util">UUID</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3279">getClusterIds</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html?is-external=true" title="class or interface in java.util">UUID</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3282">getClusterIds</a>()</pre>
 </li>
 </ul>
 <a name="isAtomic--">
@@ -737,7 +737,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isAtomic</h4>
-<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3284">isAtomic</a>()</pre>
+<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3287">isAtomic</a>()</pre>
 </li>
 </ul>
 <a name="checkAndPrepareMutation-org.apache.hadoop.hbase.client.Mutation-long-">
@@ -746,7 +746,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPrepareMutation</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3294">checkAndPrepareMutation</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3297">checkAndPrepareMutation</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
                                        long&nbsp;timestamp)
                                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Helper method that checks and prepares only one mutation. This can be used to implement
@@ -765,7 +765,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPrepareMutation</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3306">checkAndPrepareMutation</a>(int&nbsp;index,
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3309">checkAndPrepareMutation</a>(int&nbsp;index,
                                        long&nbsp;timestamp)
                                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -780,7 +780,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>lockRowsAndBuildMiniBatch</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3368">lockRowsAndBuildMiniBatch</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;acquiredRowLocks)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3371">lockRowsAndBuildMiniBatch</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;acquiredRowLocks)
                                                                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which
  a row lock can be acquired. All mutations with locked rows are considered to be
@@ -800,7 +800,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>createMiniBatch</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3452">createMiniBatch</a>(int&nbsp;lastIndexExclusive,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3455">createMiniBatch</a>(int&nbsp;lastIndexExclusive,
                                                                  int&nbsp;readyToWriteCount)</pre>
 </li>
 </ul>
@@ -810,7 +810,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>buildWALEdits</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/NonceKey.html" title="class in org.apache.hadoop.hbase.util">NonceKey</a>,<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3462">buildWALEdits</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp)
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/NonceKey.html" title="class in org.apache.hadoop.hbase.util">NonceKey</a>,<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3465">buildWALEdits</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp)
                                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are
  present, they are merged to result WALEdit.</div>
@@ -826,7 +826,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>completeMiniBatchOperations</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3511">completeMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3514">completeMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                         <a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;writeEntry)
                                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">This method completes mini-batch operations by calling postBatchMutate() CP hook (if
@@ -843,7 +843,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doPostOpCleanupForMiniBatch</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3519">doPostOpCleanupForMiniBatch</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3522">doPostOpCleanupForMiniBatch</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                         <a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
                                         boolean&nbsp;success)
                                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -859,7 +859,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doFinishHotnessProtector</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3525">doFinishHotnessProtector</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp)</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3528">doFinishHotnessProtector</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp)</pre>
 </li>
 </ul>
 <a name="applyFamilyMapToMemStore-java.util.Map-org.apache.hadoop.hbase.regionserver.MemStoreSizing-">
@@ -868,7 +868,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>applyFamilyMapToMemStore</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3562">applyFamilyMapToMemStore</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#line.3565">applyFamilyMapToMemStore</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
                                         <a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSizing.html" title="interface in org.apache.hadoop.hbase.regionserver">MemStoreSizing</a>&nbsp;memstoreAccounting)
                                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Atomically apply the given map of family->edits to the memstore.
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
index e999235..5424158 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
@@ -109,7 +109,7 @@
 </dl>
 <hr>
 <br>
-<pre>public static interface <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6152">HRegion.BulkLoadListener</a></pre>
+<pre>public static interface <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6155">HRegion.BulkLoadListener</a></pre>
 <div class="block">Listener class to enable callers of
  bulkLoadHFile() to perform any necessary
  pre/post processing of a given bulkload call</div>
@@ -174,7 +174,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>prepareBulkLoad</h4>
-<pre><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html#line.6160">prepareBulkLoad</a>(byte[]&nbsp;family,
+<pre><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html#line.6163">prepareBulkLoad</a>(byte[]&nbsp;family,
                        <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;srcPath,
                        boolean&nbsp;copyFile)
                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -196,7 +196,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doneBulkLoad</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html#line.6169">doneBulkLoad</a>(byte[]&nbsp;family,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html#line.6172">doneBulkLoad</a>(byte[]&nbsp;family,
                   <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;srcPath)
            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Called after a successful HFile load</div>
@@ -215,7 +215,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>failedBulkLoad</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html#line.6177">failedBulkLoad</a>(byte[]&nbsp;family,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html#line.6180">failedBulkLoad</a>(byte[]&nbsp;family,
                     <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;srcPath)
              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Called after a failed HFile load</div>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html
index f9c8ad3..ebb03a0 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html
@@ -122,7 +122,7 @@
 </dl>
 <hr>
 <br>
-<pre>public static enum <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2315">HRegion.FlushResult.Result</a>
+<pre>public static enum <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2318">HRegion.FlushResult.Result</a>
 extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html?is-external=true" title="class or interface in java.lang">Enum</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a>&gt;</pre>
 </li>
 </ul>
@@ -216,7 +216,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>FLUSHED_NO_COMPACTION_NEEDED</h4>
-<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2316">FLUSHED_NO_COMPACTION_NEEDED</a></pre>
+<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2319">FLUSHED_NO_COMPACTION_NEEDED</a></pre>
 </li>
 </ul>
 <a name="FLUSHED_COMPACTION_NEEDED">
@@ -225,7 +225,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>FLUSHED_COMPACTION_NEEDED</h4>
-<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2317">FLUSHED_COMPACTION_NEEDED</a></pre>
+<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2320">FLUSHED_COMPACTION_NEEDED</a></pre>
 </li>
 </ul>
 <a name="CANNOT_FLUSH_MEMSTORE_EMPTY">
@@ -234,7 +234,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>CANNOT_FLUSH_MEMSTORE_EMPTY</h4>
-<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2320">CANNOT_FLUSH_MEMSTORE_EMPTY</a></pre>
+<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2323">CANNOT_FLUSH_MEMSTORE_EMPTY</a></pre>
 </li>
 </ul>
 <a name="CANNOT_FLUSH">
@@ -243,7 +243,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>CANNOT_FLUSH</h4>
-<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2321">CANNOT_FLUSH</a></pre>
+<pre>public static final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html#line.2324">CANNOT_FLUSH</a></pre>
 </li>
 </ul>
 </li>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html
index 19daba1..4db9291 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html
@@ -109,7 +109,7 @@
 </dl>
 <hr>
 <br>
-<pre>public static interface <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2314">HRegion.FlushResult</a></pre>
+<pre>public static interface <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2317">HRegion.FlushResult</a></pre>
 </li>
 </ul>
 </div>
@@ -180,7 +180,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getResult</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2325">getResult</a>()</pre>
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html" title="enum in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult.Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2328">getResult</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>the detailed result code</dd>
@@ -193,7 +193,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isFlushSucceeded</h4>
-<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2328">isFlushSucceeded</a>()</pre>
+<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2331">isFlushSucceeded</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>true if the memstores were flushed, else false</dd>
@@ -206,7 +206,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>isCompactionNeeded</h4>
-<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2331">isCompactionNeeded</a>()</pre>
+<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html#line.2334">isCompactionNeeded</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>True if the flush requested a compaction, else false</dd>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html
index 9b7f3c7e..713e908 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html
@@ -118,7 +118,7 @@
 </dl>
 <hr>
 <br>
-<pre>static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3578">HRegion.MutationBatchOperation</a>
+<pre>static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3581">HRegion.MutationBatchOperation</a>
 extends <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;</pre>
 <div class="block">Batch of mutation operations. Base class is shared with <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver"><code>HRegion.ReplayBatchOperation</code></a> as most
  of the logic is same.</div>
@@ -342,7 +342,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>nonceGroup</h4>
-<pre>private&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3579">nonceGroup</a></pre>
+<pre>private&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3582">nonceGroup</a></pre>
 </li>
 </ul>
 <a name="nonce">
@@ -351,7 +351,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>nonce</h4>
-<pre>private&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3580">nonce</a></pre>
+<pre>private&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3583">nonce</a></pre>
 </li>
 </ul>
 </li>
@@ -368,7 +368,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>MutationBatchOperation</h4>
-<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3581">MutationBatchOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
+<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3584">MutationBatchOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
                               <a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;operations,
                               boolean&nbsp;atomic,
                               long&nbsp;nonceGroup,
@@ -389,7 +389,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMutation</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3590">getMutation</a>(int&nbsp;index)</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3593">getMutation</a>(int&nbsp;index)</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getMutation-int-">getMutation</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;</code></dd>
@@ -402,7 +402,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getNonceGroup</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3595">getNonceGroup</a>(int&nbsp;index)</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3598">getNonceGroup</a>(int&nbsp;index)</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getNonceGroup-int-">getNonceGroup</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;</code></dd>
@@ -415,7 +415,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getNonce</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3600">getNonce</a>(int&nbsp;index)</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3603">getNonce</a>(int&nbsp;index)</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getNonce-int-">getNonce</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;</code></dd>
@@ -428,7 +428,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMutationsForCoprocs</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3605">getMutationsForCoprocs</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3608">getMutationsForCoprocs</a>()</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getMutationsForCoprocs--">HRegion.BatchOperation</a></code></span></div>
 <div class="block">This method is potentially expensive and useful mostly for non-replay CP path.</div>
 <dl>
@@ -443,7 +443,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isInReplay</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3610">isInReplay</a>()</pre>
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3613">isInReplay</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#isInReplay--">isInReplay</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;</code></dd>
@@ -456,7 +456,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOrigLogSeqNum</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3615">getOrigLogSeqNum</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3618">getOrigLogSeqNum</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getOrigLogSeqNum--">getOrigLogSeqNum</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;</code></dd>
@@ -469,7 +469,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>startRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3620">startRegionOperation</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3623">startRegionOperation</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -485,7 +485,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>closeRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3625">closeRegionOperation</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3628">closeRegionOperation</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -501,7 +501,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPreparePut</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3630">checkAndPreparePut</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;p)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3633">checkAndPreparePut</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;p)
                         throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#checkAndPreparePut-org.apache.hadoop.hbase.client.Put-">HRegion.BatchOperation</a></code></span></div>
 <div class="block">Implement any Put request specific check and prepare logic here. Please refer to
@@ -520,7 +520,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPrepare</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3635">checkAndPrepare</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3638">checkAndPrepare</a>()
                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#checkAndPrepare--">HRegion.BatchOperation</a></code></span></div>
 <div class="block">Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs
@@ -542,7 +542,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>prepareMiniBatchOperations</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3680">prepareMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3683">prepareMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                        long&nbsp;timestamp,
                                        <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;acquiredRowLocks)
                                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -563,7 +563,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>buildWALEdits</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/NonceKey.html" title="class in org.apache.hadoop.hbase.util">NonceKey</a>,<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3716">buildWALEdits</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp)
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/NonceKey.html" title="class in org.apache.hadoop.hbase.util">NonceKey</a>,<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3719">buildWALEdits</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp)
                                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#buildWALEdits-org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress-">HRegion.BatchOperation</a></code></span></div>
 <div class="block">Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are
@@ -582,7 +582,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>writeMiniBatchOperationsToMemStore</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3727">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3730">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                                                                     @Nullable
                                                                                     <a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;writeEntry)
                                                                              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -602,7 +602,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>completeMiniBatchOperations</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3738">completeMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3741">completeMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                         <a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;writeEntry)
                                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#completeMiniBatchOperations-org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress-org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl.WriteEntry-">HRegion.BatchOperation</a></code></span></div>
@@ -622,7 +622,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doPostOpCleanupForMiniBatch</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3750">doPostOpCleanupForMiniBatch</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3753">doPostOpCleanupForMiniBatch</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                         <a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
                                         boolean&nbsp;success)
                                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -640,7 +640,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>callPreMutateCPHook</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3799">callPreMutateCPHook</a>(int&nbsp;index,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3802">callPreMutateCPHook</a>(int&nbsp;index,
                                  <a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
                                  int[]&nbsp;metrics)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -659,7 +659,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndMergeCPMutations</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3836">checkAndMergeCPMutations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3839">checkAndMergeCPMutations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                       <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;acquiredRowLocks,
                                       long&nbsp;timestamp)
                                throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -675,7 +675,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>mergeFamilyMaps</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3872">mergeFamilyMaps</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html#line.3875">mergeFamilyMaps</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
                              <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;toBeMerged)</pre>
 </li>
 </ul>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html
index 5a6cee6..84ee6cd 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html
@@ -121,7 +121,7 @@
 </dl>
 <hr>
 <br>
-<pre>class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6406">HRegion.RegionScannerImpl</a>
+<pre>class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6409">HRegion.RegionScannerImpl</a>
 extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>
 implements <a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">RegionScanner</a>, <a href="../../../../../org/apache/hadoop/hbase/regionserver/Shipper.html" title="interface in org.apache.hadoop.hbase.regionserver">Shipper</a>, <a href="../../../../../org/apache/hadoop/hbase/ipc/RpcCallback.html" title="interface in org.apache.hadoop.hbase.ipc">RpcCallback</a></pre>
 <div class="block">RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).</div>
@@ -425,7 +425,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>storeHeap</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueHeap.html" title="class in org.apache.hadoop.hbase.regionserver">KeyValueHeap</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6409">storeHeap</a></pre>
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueHeap.html" title="class in org.apache.hadoop.hbase.regionserver">KeyValueHeap</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6412">storeHeap</a></pre>
 </li>
 </ul>
 <a name="joinedHeap">
@@ -434,7 +434,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>joinedHeap</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueHeap.html" title="class in org.apache.hadoop.hbase.regionserver">KeyValueHeap</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6412">joinedHeap</a></pre>
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueHeap.html" title="class in org.apache.hadoop.hbase.regionserver">KeyValueHeap</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6415">joinedHeap</a></pre>
 <div class="block">Heap of key-values that are not essential for the provided filters and are thus read
  on demand, if on-demand column family loading is enabled.</div>
 </li>
@@ -445,7 +445,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>joinedContinuationRow</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6416">joinedContinuationRow</a></pre>
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6419">joinedContinuationRow</a></pre>
 <div class="block">If the joined heap data gathering is interrupted due to scan limits, this will
  contain the row for which we are populating the values.</div>
 </li>
@@ -456,7 +456,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>filterClosed</h4>
-<pre>private&nbsp;boolean <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6417">filterClosed</a></pre>
+<pre>private&nbsp;boolean <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6420">filterClosed</a></pre>
 </li>
 </ul>
 <a name="stopRow">
@@ -465,7 +465,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>stopRow</h4>
-<pre>protected final&nbsp;byte[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6419">stopRow</a></pre>
+<pre>protected final&nbsp;byte[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6422">stopRow</a></pre>
 </li>
 </ul>
 <a name="includeStopRow">
@@ -474,7 +474,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>includeStopRow</h4>
-<pre>protected final&nbsp;boolean <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6420">includeStopRow</a></pre>
+<pre>protected final&nbsp;boolean <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6423">includeStopRow</a></pre>
 </li>
 </ul>
 <a name="region">
@@ -483,7 +483,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>region</h4>
-<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6421">region</a></pre>
+<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6424">region</a></pre>
 </li>
 </ul>
 <a name="comparator">
@@ -492,7 +492,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>comparator</h4>
-<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/CellComparator.html" title="interface in org.apache.hadoop.hbase">CellComparator</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6422">comparator</a></pre>
+<pre>protected final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/CellComparator.html" title="interface in org.apache.hadoop.hbase">CellComparator</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6425">comparator</a></pre>
 </li>
 </ul>
 <a name="readPt">
@@ -501,7 +501,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>readPt</h4>
-<pre>private final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6424">readPt</a></pre>
+<pre>private final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6427">readPt</a></pre>
 </li>
 </ul>
 <a name="maxResultSize">
@@ -510,7 +510,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>maxResultSize</h4>
-<pre>private final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6425">maxResultSize</a></pre>
+<pre>private final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6428">maxResultSize</a></pre>
 </li>
 </ul>
 <a name="defaultScannerContext">
@@ -519,7 +519,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>defaultScannerContext</h4>
-<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6426">defaultScannerContext</a></pre>
+<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6429">defaultScannerContext</a></pre>
 </li>
 </ul>
 <a name="filter">
@@ -528,7 +528,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>filter</h4>
-<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/filter/FilterWrapper.html" title="class in org.apache.hadoop.hbase.filter">FilterWrapper</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6427">filter</a></pre>
+<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/filter/FilterWrapper.html" title="class in org.apache.hadoop.hbase.filter">FilterWrapper</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6430">filter</a></pre>
 </li>
 </ul>
 </li>
@@ -545,7 +545,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>RegionScannerImpl</h4>
-<pre><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6434">RegionScannerImpl</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
+<pre><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6437">RegionScannerImpl</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
                   <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;additionalScanners,
                   <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region)
            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -561,7 +561,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>RegionScannerImpl</h4>
-<pre><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6439">RegionScannerImpl</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
+<pre><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6442">RegionScannerImpl</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
                   <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;additionalScanners,
                   <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
                   long&nbsp;nonceGroup,
@@ -587,7 +587,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRegionInfo</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6430">getRegionInfo</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6433">getRegionInfo</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html#getRegionInfo--">getRegionInfo</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">RegionScanner</a></code></dd>
@@ -602,7 +602,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>initializeScanners</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6477">initializeScanners</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6480">initializeScanners</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
                                   <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;additionalScanners)
                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -617,7 +617,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>initializeKVHeap</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6509">initializeKVHeap</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;scanners,
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6512">initializeKVHeap</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;scanners,
                                 <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;joinedScanners,
                                 <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region)
                          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -633,7 +633,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>handleException</h4>
-<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6518">handleException</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;instantiatedScanners,
+<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6521">handleException</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;instantiatedScanners,
                                     <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Throwable.html?is-external=true" title="class or interface in java.lang">Throwable</a>&nbsp;t)</pre>
 </li>
 </ul>
@@ -643,7 +643,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMaxResultSize</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6539">getMaxResultSize</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6542">getMaxResultSize</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html#getMaxResultSize--">getMaxResultSize</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">RegionScanner</a></code></dd>
@@ -659,7 +659,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMvccReadPoint</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6544">getMvccReadPoint</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6547">getMvccReadPoint</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html#getMvccReadPoint--">getMvccReadPoint</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">RegionScanner</a></code></dd>
@@ -674,7 +674,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getBatch</h4>
-<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6549">getBatch</a>()</pre>
+<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6552">getBatch</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html#getBatch--">getBatch</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">RegionScanner</a></code></dd>
@@ -690,7 +690,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>resetFilters</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6558">resetFilters</a>()
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6561">resetFilters</a>()
                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Reset both the filter and the old filter.</div>
 <dl>
@@ -705,7 +705,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>next</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6565">next</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults)
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6568">next</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults)
              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/InternalScanner.html#next-java.util.List-">InternalScanner</a></code></span></div>
 <div class="block">Grab the next row's worth of values.</div>
@@ -727,7 +727,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>next</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6572">next</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults,
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6575">next</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults,
                     <a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)
              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/InternalScanner.html#next-java.util.List-org.apache.hadoop.hbase.regionserver.ScannerContext-">InternalScanner</a></code></span></div>
@@ -750,7 +750,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>nextRaw</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6588">nextRaw</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults)
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6591">nextRaw</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults)
                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html#nextRaw-java.util.List-">RegionScanner</a></code></span></div>
 <div class="block">Grab the next row's worth of values. This is a special internal method to be called from
@@ -775,7 +775,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>nextRaw</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6594">nextRaw</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults,
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6597">nextRaw</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;outResults,
                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)
                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html#nextRaw-java.util.List-org.apache.hadoop.hbase.regionserver.ScannerContext-">RegionScanner</a></code></span></div>
@@ -821,7 +821,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>populateFromJoinedHeap</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6631">populateFromJoinedHeap</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6634">populateFromJoinedHeap</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
                                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)
                                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -838,7 +838,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>populateResult</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6655">populateResult</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6658">populateResult</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
                                <a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueHeap.html" title="class in org.apache.hadoop.hbase.regionserver">KeyValueHeap</a>&nbsp;heap,
                                <a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext,
                                <a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;currentRowCell)
@@ -863,7 +863,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>moreCellsInRow</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6696">moreCellsInRow</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;nextKv,
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6699">moreCellsInRow</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;nextKv,
                                <a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;currentRowCell)</pre>
 <div class="block">Based on the nextKv in the heap, and the current row, decide whether or not there are more
  cells to be read in the heap. If the row of the nextKv in the heap matches the current row
@@ -883,7 +883,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isFilterDone</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6704">isFilterDone</a>()
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6707">isFilterDone</a>()
                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -901,7 +901,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isFilterDoneInternal</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6708">isFilterDoneInternal</a>()
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6711">isFilterDoneInternal</a>()
                               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -915,7 +915,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>nextInternal</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6712">nextInternal</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6715">nextInternal</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
                              <a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)
                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -930,7 +930,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>incrementCountOfRowsFilteredMetric</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6935">incrementCountOfRowsFilteredMetric</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)</pre>
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6938">incrementCountOfRowsFilteredMetric</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)</pre>
 </li>
 </ul>
 <a name="incrementCountOfRowsScannedMetric-org.apache.hadoop.hbase.regionserver.ScannerContext-">
@@ -939,7 +939,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>incrementCountOfRowsScannedMetric</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6943">incrementCountOfRowsScannedMetric</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)</pre>
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6946">incrementCountOfRowsScannedMetric</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext)</pre>
 </li>
 </ul>
 <a name="joinedHeapMayHaveData-org.apache.hadoop.hbase.Cell-">
@@ -948,7 +948,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>joinedHeapMayHaveData</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6954">joinedHeapMayHaveData</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;currentRowCell)
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6957">joinedHeapMayHaveData</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;currentRowCell)
                                throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="paramLabel">Parameters:</span></dt>
@@ -966,7 +966,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>filterRow</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6981">filterRow</a>()
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6984">filterRow</a>()
                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines
  both filterRow & filterRow(<code>List&lt;KeyValue&gt; kvs</code>) functions. While 0.94 code or older,
@@ -985,7 +985,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>filterRowKey</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6988">filterRowKey</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;current)
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6991">filterRowKey</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;current)
                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -999,7 +999,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>nextRow</h4>
-<pre>protected&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6992">nextRow</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext,
+<pre>protected&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.6995">nextRow</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/ScannerContext.html" title="class in org.apache.hadoop.hbase.regionserver">ScannerContext</a>&nbsp;scannerContext,
                           <a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;curRowCell)
                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -1014,7 +1014,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>shouldStop</h4>
-<pre>protected&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7007">shouldStop</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;currentRowCell)</pre>
+<pre>protected&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7010">shouldStop</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;currentRowCell)</pre>
 </li>
 </ul>
 <a name="close--">
@@ -1023,7 +1023,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>close</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7019">close</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7022">close</a>()</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/InternalScanner.html#close--">InternalScanner</a></code></span></div>
 <div class="block">Closes the scanner and releases any resources it has allocated</div>
 <dl>
@@ -1042,7 +1042,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStoreHeapForTesting</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueHeap.html" title="class in org.apache.hadoop.hbase.regionserver">KeyValueHeap</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7033">getStoreHeapForTesting</a>()</pre>
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueHeap.html" title="class in org.apache.hadoop.hbase.regionserver">KeyValueHeap</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7036">getStoreHeapForTesting</a>()</pre>
 </li>
 </ul>
 <a name="reseek-byte:A-">
@@ -1051,7 +1051,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>reseek</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7038">reseek</a>(byte[]&nbsp;row)
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7041">reseek</a>(byte[]&nbsp;row)
                throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html#reseek-byte:A-">RegionScanner</a></code></span></div>
 <div class="block">Do a reseek to the required row. Should not be used to seek to a key which
@@ -1071,7 +1071,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>shipped</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7058">shipped</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7061">shipped</a>()
              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Shipper.html#shipped--">Shipper</a></code></span></div>
 <div class="block">Called after a batch of rows scanned and set to be returned to client. Any in between cleanup
@@ -1090,7 +1090,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>run</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7068">run</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html#line.7071">run</a>()
          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/ipc/RpcCallback.html#run--">RpcCallback</a></code></span></div>
 <div class="block">Called at the end of an Rpc Call <a href="../../../../../org/apache/hadoop/hbase/ipc/RpcCallContext.html" title="interface in org.apache.hadoop.hbase.ipc"><code>RpcCallContext</code></a></div>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html
index f6e10fe..989bdc6 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html
@@ -118,7 +118,7 @@
 </dl>
 <hr>
 <br>
-<pre>static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3889">HRegion.ReplayBatchOperation</a>
+<pre>static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3892">HRegion.ReplayBatchOperation</a>
 extends <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>&gt;</pre>
 <div class="block">Batch of mutations for replay. Base class is shared with <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver"><code>HRegion.MutationBatchOperation</code></a> as most
  of the logic is same.</div>
@@ -306,7 +306,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>origLogSeqNum</h4>
-<pre>private&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3890">origLogSeqNum</a></pre>
+<pre>private&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3893">origLogSeqNum</a></pre>
 </li>
 </ul>
 </li>
@@ -323,7 +323,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>ReplayBatchOperation</h4>
-<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3891">ReplayBatchOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
+<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3894">ReplayBatchOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
                             <a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>[]&nbsp;operations,
                             long&nbsp;origLogSeqNum)</pre>
 </li>
@@ -342,7 +342,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMutation</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3898">getMutation</a>(int&nbsp;index)</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3901">getMutation</a>(int&nbsp;index)</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getMutation-int-">getMutation</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>&gt;</code></dd>
@@ -355,7 +355,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getNonceGroup</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3903">getNonceGroup</a>(int&nbsp;index)</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3906">getNonceGroup</a>(int&nbsp;index)</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getNonceGroup-int-">getNonceGroup</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>&gt;</code></dd>
@@ -368,7 +368,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getNonce</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3908">getNonce</a>(int&nbsp;index)</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3911">getNonce</a>(int&nbsp;index)</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getNonce-int-">getNonce</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>&gt;</code></dd>
@@ -381,7 +381,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMutationsForCoprocs</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3913">getMutationsForCoprocs</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3916">getMutationsForCoprocs</a>()</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getMutationsForCoprocs--">HRegion.BatchOperation</a></code></span></div>
 <div class="block">This method is potentially expensive and useful mostly for non-replay CP path.</div>
 <dl>
@@ -396,7 +396,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isInReplay</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3918">isInReplay</a>()</pre>
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3921">isInReplay</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#isInReplay--">isInReplay</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>&gt;</code></dd>
@@ -409,7 +409,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOrigLogSeqNum</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3923">getOrigLogSeqNum</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3926">getOrigLogSeqNum</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#getOrigLogSeqNum--">getOrigLogSeqNum</a></code>&nbsp;in class&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>&gt;</code></dd>
@@ -422,7 +422,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>startRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3928">startRegionOperation</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3931">startRegionOperation</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -438,7 +438,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>closeRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3933">closeRegionOperation</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3936">closeRegionOperation</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -454,7 +454,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPreparePut</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3942">checkAndPreparePut</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;p)
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3945">checkAndPreparePut</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;p)
                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">During replay, there could exist column families which are removed between region server
  failure and replay</div>
@@ -472,7 +472,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndPrepare</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3963">checkAndPrepare</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3966">checkAndPrepare</a>()
                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#checkAndPrepare--">HRegion.BatchOperation</a></code></span></div>
 <div class="block">Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs
@@ -494,7 +494,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>prepareMiniBatchOperations</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3972">prepareMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3975">prepareMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                        long&nbsp;timestamp,
                                        <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;acquiredRowLocks)
                                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -515,7 +515,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>writeMiniBatchOperationsToMemStore</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3984">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3987">writeMiniBatchOperationsToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                                                                     <a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;writeEntry)
                                                                              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#writeMiniBatchOperationsToMemStore-org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress-org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl.WriteEntry-">HRegion.BatchOperation</a></code></span></div>
@@ -534,7 +534,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>completeMiniBatchOperations</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3992">completeMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html#line.3995">completeMiniBatchOperations</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MiniBatchOperationInProgress.html" title="class in org.apache.hadoop.hbase.regionserver">MiniBatchOperationInProgress</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;miniBatchOp,
                                         <a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;writeEntry)
                                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from class:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html#completeMiniBatchOperations-org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress-org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl.WriteEntry-">HRegion.BatchOperation</a></code></span></div>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html
index ef08086..6e0e203 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html
@@ -113,7 +113,7 @@
 </dl>
 <hr>
 <br>
-<pre>class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6014">HRegion.RowLockContext</a>
+<pre>class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6017">HRegion.RowLockContext</a>
 extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></pre>
 </li>
 </ul>
@@ -241,7 +241,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>row</h4>
-<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/util/HashedBytes.html" title="class in org.apache.hadoop.hbase.util">HashedBytes</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6015">row</a></pre>
+<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/util/HashedBytes.html" title="class in org.apache.hadoop.hbase.util">HashedBytes</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6018">row</a></pre>
 </li>
 </ul>
 <a name="readWriteLock">
@@ -250,7 +250,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>readWriteLock</h4>
-<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReadWriteLock.html?is-external=true" title="class or interface in java.util.concurrent.locks">ReadWriteLock</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6016">readWriteLock</a></pre>
+<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReadWriteLock.html?is-external=true" title="class or interface in java.util.concurrent.locks">ReadWriteLock</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6019">readWriteLock</a></pre>
 </li>
 </ul>
 <a name="usable">
@@ -259,7 +259,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>usable</h4>
-<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicBoolean.html?is-external=true" title="class or interface in java.util.concurrent.atomic">AtomicBoolean</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6017">usable</a></pre>
+<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicBoolean.html?is-external=true" title="class or interface in java.util.concurrent.atomic">AtomicBoolean</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6020">usable</a></pre>
 </li>
 </ul>
 <a name="count">
@@ -268,7 +268,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>count</h4>
-<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicInteger.html?is-external=true" title="class or interface in java.util.concurrent.atomic">AtomicInteger</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6018">count</a></pre>
+<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicInteger.html?is-external=true" title="class or interface in java.util.concurrent.atomic">AtomicInteger</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6021">count</a></pre>
 </li>
 </ul>
 <a name="lock">
@@ -277,7 +277,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>lock</h4>
-<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6019">lock</a></pre>
+<pre>final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6022">lock</a></pre>
 </li>
 </ul>
 <a name="threadName">
@@ -286,7 +286,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>threadName</h4>
-<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6020">threadName</a></pre>
+<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6023">threadName</a></pre>
 </li>
 </ul>
 </li>
@@ -303,7 +303,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>RowLockContext</h4>
-<pre><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6022">RowLockContext</a>(<a href="../../../../../org/apache/hadoop/hbase/util/HashedBytes.html" title="class in org.apache.hadoop.hbase.util">HashedBytes</a>&nbsp;row)</pre>
+<pre><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6025">RowLockContext</a>(<a href="../../../../../org/apache/hadoop/hbase/util/HashedBytes.html" title="class in org.apache.hadoop.hbase.util">HashedBytes</a>&nbsp;row)</pre>
 </li>
 </ul>
 </li>
@@ -320,7 +320,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>newWriteLock</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6026">newWriteLock</a>()</pre>
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6029">newWriteLock</a>()</pre>
 </li>
 </ul>
 <a name="newReadLock--">
@@ -329,7 +329,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>newReadLock</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6030">newReadLock</a>()</pre>
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6033">newReadLock</a>()</pre>
 </li>
 </ul>
 <a name="getRowLock-java.util.concurrent.locks.Lock-">
@@ -338,7 +338,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRowLock</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6035">getRowLock</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;l)</pre>
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6038">getRowLock</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;l)</pre>
 </li>
 </ul>
 <a name="cleanUp--">
@@ -347,7 +347,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>cleanUp</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6046">cleanUp</a>()</pre>
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6049">cleanUp</a>()</pre>
 </li>
 </ul>
 <a name="setThreadName-java.lang.String-">
@@ -356,7 +356,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setThreadName</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6059">setThreadName</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;threadName)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6062">setThreadName</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;threadName)</pre>
 </li>
 </ul>
 <a name="toString--">
@@ -365,7 +365,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>toString</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6064">toString</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html#line.6067">toString</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Overrides:</span></dt>
 <dd><code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true#toString--" title="class or interface in java.lang">toString</a></code>&nbsp;in class&nbsp;<code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></code></dd>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html
index f282f08..8d2ac9d 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html
@@ -117,7 +117,7 @@
 </dl>
 <hr>
 <br>
-<pre>public static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6077">HRegion.RowLockImpl</a>
+<pre>public static class <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6080">HRegion.RowLockImpl</a>
 extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>
 implements <a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a></pre>
 <div class="block">Class used to represent a lock on a row.</div>
@@ -226,7 +226,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>context</h4>
-<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6078">context</a></pre>
+<pre>private final&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6081">context</a></pre>
 </li>
 </ul>
 <a name="lock">
@@ -235,7 +235,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>lock</h4>
-<pre>private final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6079">lock</a></pre>
+<pre>private final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a> <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6082">lock</a></pre>
 </li>
 </ul>
 </li>
@@ -252,7 +252,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>RowLockImpl</h4>
-<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6081">RowLockImpl</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a>&nbsp;context,
+<pre>public&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6084">RowLockImpl</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a>&nbsp;context,
                    <a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;lock)</pre>
 </li>
 </ul>
@@ -270,7 +270,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getLock</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6086">getLock</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6089">getLock</a>()</pre>
 </li>
 </ul>
 <a name="getContext--">
@@ -279,7 +279,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getContext</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6091">getContext</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6094">getContext</a>()</pre>
 </li>
 </ul>
 <a name="release--">
@@ -288,7 +288,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>release</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6096">release</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6099">release</a>()</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html#release--">Region.RowLock</a></code></span></div>
 <div class="block">Release the given lock.  If there are no remaining locks held by the current thread
  then unlock the row and allow other threads to acquire the lock.</div>
@@ -304,7 +304,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>toString</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6102">toString</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html#line.6105">toString</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Overrides:</span></dt>
 <dd><code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true#toString--" title="class or interface in java.lang">toString</a></code>&nbsp;in class&nbsp;<code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></code></dd>
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.html b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.html
index f788fa9..d70d693 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/HRegion.html
@@ -3368,7 +3368,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>FOR_UNIT_TESTS_ONLY</h4>
-<pre>private static final&nbsp;byte[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3041">FOR_UNIT_TESTS_ONLY</a></pre>
+<pre>private static final&nbsp;byte[] <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3044">FOR_UNIT_TESTS_ONLY</a></pre>
 <div class="block">Row needed by below method.</div>
 </li>
 </ul>
@@ -3378,7 +3378,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>FIXED_OVERHEAD</h4>
-<pre>public static final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8215">FIXED_OVERHEAD</a></pre>
+<pre>public static final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8218">FIXED_OVERHEAD</a></pre>
 </li>
 </ul>
 <a name="DEEP_OVERHEAD">
@@ -3387,7 +3387,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>DEEP_OVERHEAD</h4>
-<pre>public static final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8232">DEEP_OVERHEAD</a></pre>
+<pre>public static final&nbsp;long <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8235">DEEP_OVERHEAD</a></pre>
 </li>
 </ul>
 <a name="MOCKED_LIST">
@@ -3396,7 +3396,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>MOCKED_LIST</h4>
-<pre>private static final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt; <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8626">MOCKED_LIST</a></pre>
+<pre>private static final&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt; <a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8629">MOCKED_LIST</a></pre>
 <div class="block">A mocked list implementation - discards all updates.</div>
 </li>
 </ul>
@@ -4248,7 +4248,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setClosing</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1563">setClosing</a>(boolean&nbsp;closing)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1566">setClosing</a>(boolean&nbsp;closing)</pre>
 <div class="block">Exposed for some very specific unit tests.</div>
 </li>
 </ul>
@@ -4258,7 +4258,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setTimeoutForWriteLock</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1573">setTimeoutForWriteLock</a>(long&nbsp;timeoutForWriteLock)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1576">setTimeoutForWriteLock</a>(long&nbsp;timeoutForWriteLock)</pre>
 <div class="block">The <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html#doClose-boolean-org.apache.hadoop.hbase.monitoring.MonitoredTask-"><code>doClose(boolean, org.apache.hadoop.hbase.monitoring.MonitoredTask)</code></a> will block forever if someone tries proving the dead lock via the unit test.
  Instead of blocking, the <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html#doClose-boolean-org.apache.hadoop.hbase.monitoring.MonitoredTask-"><code>doClose(boolean, org.apache.hadoop.hbase.monitoring.MonitoredTask)</code></a> will throw exception if you set the timeout.</div>
 <dl>
@@ -4273,7 +4273,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doClose</h4>
-<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStoreFile.html" title="class in org.apache.hadoop.hbase.regionserver">HStoreFile</a>&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1580">doClose</a>(boolean&nbsp;abort,
+<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStoreFile.html" title="class in org.apache.hadoop.hbase.regionserver">HStoreFile</a>&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1583">doClose</a>(boolean&nbsp;abort,
                                              <a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status)
                                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -4288,7 +4288,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>waitForFlushesAndCompactions</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1765">waitForFlushesAndCompactions</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1768">waitForFlushesAndCompactions</a>()</pre>
 <div class="block">Wait for all current flushes and compactions of the region to complete</div>
 </li>
 </ul>
@@ -4298,7 +4298,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>waitForFlushes</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1797">waitForFlushes</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1800">waitForFlushes</a>()</pre>
 <div class="block">Wait for all current flushes of the region to complete</div>
 </li>
 </ul>
@@ -4308,7 +4308,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>waitForFlushes</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1802">waitForFlushes</a>(long&nbsp;timeout)</pre>
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1805">waitForFlushes</a>(long&nbsp;timeout)</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#waitForFlushes-long-">Region</a></code></span></div>
 <div class="block">Wait for all current flushes of the region to complete</div>
 <dl>
@@ -4328,7 +4328,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStoreOpenAndCloseThreadPool</h4>
-<pre>protected&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html?is-external=true" title="class or interface in java.util.concurrent">ThreadPoolExecutor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1839">getStoreOpenAndCloseThreadPool</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;threadNamePrefix)</pre>
+<pre>protected&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html?is-external=true" title="class or interface in java.util.concurrent">ThreadPoolExecutor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1842">getStoreOpenAndCloseThreadPool</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;threadNamePrefix)</pre>
 </li>
 </ul>
 <a name="getStoreFileOpenAndCloseThreadPool-java.lang.String-">
@@ -4337,7 +4337,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStoreFileOpenAndCloseThreadPool</h4>
-<pre>protected&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html?is-external=true" title="class or interface in java.util.concurrent">ThreadPoolExecutor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1848">getStoreFileOpenAndCloseThreadPool</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;threadNamePrefix)</pre>
+<pre>protected&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html?is-external=true" title="class or interface in java.util.concurrent">ThreadPoolExecutor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1851">getStoreFileOpenAndCloseThreadPool</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;threadNamePrefix)</pre>
 </li>
 </ul>
 <a name="getOpenAndCloseThreadPool-int-java.lang.String-">
@@ -4346,7 +4346,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOpenAndCloseThreadPool</h4>
-<pre>static&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html?is-external=true" title="class or interface in java.util.concurrent">ThreadPoolExecutor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1858">getOpenAndCloseThreadPool</a>(int&nbsp;maxThreads,
+<pre>static&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html?is-external=true" title="class or interface in java.util.concurrent">ThreadPoolExecutor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1861">getOpenAndCloseThreadPool</a>(int&nbsp;maxThreads,
                                                     <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;threadNamePrefix)</pre>
 </li>
 </ul>
@@ -4356,7 +4356,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>worthPreFlushing</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1874">worthPreFlushing</a>()</pre>
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1877">worthPreFlushing</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>True if its worth doing a flush before we put up the close flag.</dd>
@@ -4369,7 +4369,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getTableDescriptor</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1884">getTableDescriptor</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1887">getTableDescriptor</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getTableDescriptor--">getTableDescriptor</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a></code></dd>
@@ -4384,7 +4384,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setTableDescriptor</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1889">setTableDescriptor</a>(<a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;desc)</pre>
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1892">setTableDescriptor</a>(<a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;desc)</pre>
 </li>
 </ul>
 <a name="getWAL--">
@@ -4393,7 +4393,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getWAL</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1894">getWAL</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1897">getWAL</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>WAL in use for this region</dd>
@@ -4406,7 +4406,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getBlockCache</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/io/hfile/BlockCache.html" title="interface in org.apache.hadoop.hbase.io.hfile">BlockCache</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1898">getBlockCache</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/io/hfile/BlockCache.html" title="interface in org.apache.hadoop.hbase.io.hfile">BlockCache</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1901">getBlockCache</a>()</pre>
 </li>
 </ul>
 <a name="setBlockCache-org.apache.hadoop.hbase.io.hfile.BlockCache-">
@@ -4415,7 +4415,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setBlockCache</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1906">setBlockCache</a>(<a href="../../../../../org/apache/hadoop/hbase/io/hfile/BlockCache.html" title="interface in org.apache.hadoop.hbase.io.hfile">BlockCache</a>&nbsp;blockCache)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1909">setBlockCache</a>(<a href="../../../../../org/apache/hadoop/hbase/io/hfile/BlockCache.html" title="interface in org.apache.hadoop.hbase.io.hfile">BlockCache</a>&nbsp;blockCache)</pre>
 <div class="block">Only used for unit test which doesn't start region server.</div>
 </li>
 </ul>
@@ -4425,7 +4425,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMobFileCache</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/mob/MobFileCache.html" title="class in org.apache.hadoop.hbase.mob">MobFileCache</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1910">getMobFileCache</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/mob/MobFileCache.html" title="class in org.apache.hadoop.hbase.mob">MobFileCache</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1913">getMobFileCache</a>()</pre>
 </li>
 </ul>
 <a name="setMobFileCache-org.apache.hadoop.hbase.mob.MobFileCache-">
@@ -4434,7 +4434,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setMobFileCache</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1918">setMobFileCache</a>(<a href="../../../../../org/apache/hadoop/hbase/mob/MobFileCache.html" title="class in org.apache.hadoop.hbase.mob">MobFileCache</a>&nbsp;mobFileCache)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1921">setMobFileCache</a>(<a href="../../../../../org/apache/hadoop/hbase/mob/MobFileCache.html" title="class in org.apache.hadoop.hbase.mob">MobFileCache</a>&nbsp;mobFileCache)</pre>
 <div class="block">Only used for unit test which doesn't start region server.</div>
 </li>
 </ul>
@@ -4444,7 +4444,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getSplitPolicy</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.html" title="class in org.apache.hadoop.hbase.regionserver">RegionSplitPolicy</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1925">getSplitPolicy</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.html" title="class in org.apache.hadoop.hbase.regionserver">RegionSplitPolicy</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1928">getSplitPolicy</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>split policy for this region.</dd>
@@ -4457,7 +4457,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getBaseConf</h4>
-<pre>org.apache.hadoop.conf.Configuration&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1936">getBaseConf</a>()</pre>
+<pre>org.apache.hadoop.conf.Configuration&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1939">getBaseConf</a>()</pre>
 <div class="block">A split takes the config from the parent region & passes it to the daughter
  region's constructor. If 'conf' was passed, you would end up using the HTD
  of the parent region in addition to the new daughter HTD. Pass 'baseConf'
@@ -4474,7 +4474,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getFilesystem</h4>
-<pre>public&nbsp;org.apache.hadoop.fs.FileSystem&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1941">getFilesystem</a>()</pre>
+<pre>public&nbsp;org.apache.hadoop.fs.FileSystem&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1944">getFilesystem</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd><code>FileSystem</code> being used by this region</dd>
@@ -4487,7 +4487,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRegionFileSystem</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegionFileSystem.html" title="class in org.apache.hadoop.hbase.regionserver">HRegionFileSystem</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1946">getRegionFileSystem</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegionFileSystem.html" title="class in org.apache.hadoop.hbase.regionserver">HRegionFileSystem</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1949">getRegionFileSystem</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>the <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegionFileSystem.html" title="class in org.apache.hadoop.hbase.regionserver"><code>HRegionFileSystem</code></a> used by this region</dd>
@@ -4500,7 +4500,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRegionWALFileSystem</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegionFileSystem.html" title="class in org.apache.hadoop.hbase.regionserver">HRegionFileSystem</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1951">getRegionWALFileSystem</a>()
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegionFileSystem.html" title="class in org.apache.hadoop.hbase.regionserver">HRegionFileSystem</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1954">getRegionWALFileSystem</a>()
                                   throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
@@ -4516,7 +4516,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getWalFileSystem</h4>
-<pre>org.apache.hadoop.fs.FileSystem&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1957">getWalFileSystem</a>()
+<pre>org.apache.hadoop.fs.FileSystem&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1960">getWalFileSystem</a>()
                                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
@@ -4532,7 +4532,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getWALRegionDir</h4>
-<pre>public&nbsp;org.apache.hadoop.fs.Path&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1969">getWALRegionDir</a>()
+<pre>public&nbsp;org.apache.hadoop.fs.Path&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1972">getWALRegionDir</a>()
                                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
@@ -4548,7 +4548,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getEarliestFlushTimeForAllStores</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1978">getEarliestFlushTimeForAllStores</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1981">getEarliestFlushTimeForAllStores</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getEarliestFlushTimeForAllStores--">getEarliestFlushTimeForAllStores</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a></code></dd>
@@ -4565,7 +4565,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOldestHfileTs</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1983">getOldestHfileTs</a>(boolean&nbsp;majorCompactionOnly)
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.1986">getOldestHfileTs</a>(boolean&nbsp;majorCompactionOnly)
                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getOldestHfileTs-boolean-">Region</a></code></span></div>
 <div class="block">This can be used to determine the last time all files of this region were major compacted.</div>
@@ -4587,7 +4587,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setCompleteSequenceId</h4>
-<pre>org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionLoad.Builder&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2011">setCompleteSequenceId</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionLoad.Builder&nbsp;regionLoadBldr)</pre>
+<pre>org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionLoad.Builder&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2014">setCompleteSequenceId</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionLoad.Builder&nbsp;regionLoadBldr)</pre>
 </li>
 </ul>
 <a name="doRegionCompactionPrep--">
@@ -4596,7 +4596,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doRegionCompactionPrep</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2037">doRegionCompactionPrep</a>()
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2040">doRegionCompactionPrep</a>()
                                throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Do preparation for pending compaction.</div>
 <dl>
@@ -4611,7 +4611,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>compact</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2053">compact</a>(boolean&nbsp;majorCompaction)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2056">compact</a>(boolean&nbsp;majorCompaction)
              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Synchronously compact all stores in the region.
  <p>This operation could block for a long time, so don't call it from a
@@ -4635,7 +4635,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>compactStores</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2078">compactStores</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2081">compactStores</a>()
                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">This is a helper function that compact all the stores synchronously.
  <p>
@@ -4652,7 +4652,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>compactStore</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2093">compactStore</a>(byte[]&nbsp;family,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2096">compactStore</a>(byte[]&nbsp;family,
                   <a href="../../../../../org/apache/hadoop/hbase/regionserver/throttle/ThroughputController.html" title="interface in org.apache.hadoop.hbase.regionserver.throttle">ThroughputController</a>&nbsp;throughputController)
            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">This is a helper function that compact the given store.
@@ -4670,7 +4670,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>compact</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2116">compact</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/compactions/CompactionContext.html" title="class in org.apache.hadoop.hbase.regionserver.compactions">CompactionContext</a>&nbsp;compaction,
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2119">compact</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/compactions/CompactionContext.html" title="class in org.apache.hadoop.hbase.regionserver.compactions">CompactionContext</a>&nbsp;compaction,
                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/throttle/ThroughputController.html" title="interface in org.apache.hadoop.hbase.regionserver.throttle">ThroughputController</a>&nbsp;throughputController)
                 throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -4700,7 +4700,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>shouldForbidMajorCompaction</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2121">shouldForbidMajorCompaction</a>()</pre>
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2124">shouldForbidMajorCompaction</a>()</pre>
 </li>
 </ul>
 <a name="compact-org.apache.hadoop.hbase.regionserver.compactions.CompactionContext-org.apache.hadoop.hbase.regionserver.HStore-org.apache.hadoop.hbase.regionserver.throttle.ThroughputController-org.apache.hadoop.hbase.security.User-">
@@ -4709,7 +4709,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>compact</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2203">compact</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/compactions/CompactionContext.html" title="class in org.apache.hadoop.hbase.regionserver.compactions">CompactionContext</a>&nbsp;compaction,
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2206">compact</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/compactions/CompactionContext.html" title="class in org.apache.hadoop.hbase.regionserver.compactions">CompactionContext</a>&nbsp;compaction,
                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/throttle/ThroughputController.html" title="interface in org.apache.hadoop.hbase.regionserver.throttle">ThroughputController</a>&nbsp;throughputController,
                        <a href="../../../../../org/apache/hadoop/hbase/security/User.html" title="class in org.apache.hadoop.hbase.security">User</a>&nbsp;user)
@@ -4798,7 +4798,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>flush</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html" title="interface in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2310">flush</a>(boolean&nbsp;force)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html" title="interface in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2313">flush</a>(boolean&nbsp;force)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Flush the cache.
 
@@ -4830,7 +4830,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>flushcache</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2357">flushcache</a>(boolean&nbsp;forceFlushAllStores,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2360">flushcache</a>(boolean&nbsp;forceFlushAllStores,
                                           boolean&nbsp;writeFlushRequestWalMarker,
                                           <a href="../../../../../org/apache/hadoop/hbase/regionserver/FlushLifeCycleTracker.html" title="interface in org.apache.hadoop.hbase.regionserver">FlushLifeCycleTracker</a>&nbsp;tracker)
                                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -4867,7 +4867,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>shouldFlushStore</h4>
-<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2442">shouldFlushStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store)</pre>
+<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2445">shouldFlushStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store)</pre>
 <div class="block">Should the store be flushed because it is old enough.
  <p>
  Every FlushPolicy should call this to determine whether a store is old enough to flush (except
@@ -4881,7 +4881,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>shouldFlush</h4>
-<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2471">shouldFlush</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html?is-external=true" title="class or interface in java.lang">StringBuilder</a>&nbsp;whyFlush)</pre>
+<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2474">shouldFlush</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html?is-external=true" title="class or interface in java.lang">StringBuilder</a>&nbsp;whyFlush)</pre>
 <div class="block">Should the memstore be flushed now</div>
 </li>
 </ul>
@@ -4891,7 +4891,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>internalFlushcache</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html" title="interface in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2508">internalFlushcache</a>(<a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status)
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html" title="interface in org.apache.hadoop.hbase.regionserver">HRegion.FlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2511">internalFlushcache</a>(<a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status)
                                         throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Flushing all stores.</div>
 <dl>
@@ -4908,7 +4908,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>internalFlushcache</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2516">internalFlushcache</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;storesToFlush,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2519">internalFlushcache</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;storesToFlush,
                                                    <a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status,
                                                    boolean&nbsp;writeFlushWalMarker,
                                                    <a href="../../../../../org/apache/hadoop/hbase/regionserver/FlushLifeCycleTracker.html" title="interface in org.apache.hadoop.hbase.regionserver">FlushLifeCycleTracker</a>&nbsp;tracker)
@@ -4928,7 +4928,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>internalFlushcache</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2540">internalFlushcache</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2543">internalFlushcache</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                                      long&nbsp;myseqid,
                                                      <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;storesToFlush,
                                                      <a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status,
@@ -4964,7 +4964,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>internalPrepareFlushCache</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2554">internalPrepareFlushCache</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2557">internalPrepareFlushCache</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                                                long&nbsp;myseqid,
                                                                <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;storesToFlush,
                                                                <a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status,
@@ -4983,7 +4983,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>logFatLineOnFlush</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2694">logFatLineOnFlush</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;storesToFlush,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2697">logFatLineOnFlush</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;storesToFlush,
                                long&nbsp;sequenceId)</pre>
 <div class="block">Utility method broken out of internalPrepareFlushCache so that method is smaller.</div>
 </li>
@@ -4994,7 +4994,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doAbortFlushToWAL</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2722">doAbortFlushToWAL</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2725">doAbortFlushToWAL</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                long&nbsp;flushOpSeqId,
                                <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;org.apache.hadoop.fs.Path&gt;&gt;&nbsp;committedFiles)</pre>
 </li>
@@ -5005,7 +5005,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doSyncOfUnflushedWALChanges</h4>
-<pre>private static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2742">doSyncOfUnflushedWALChanges</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
+<pre>private static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2745">doSyncOfUnflushedWALChanges</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                                 <a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;hri)
                                          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Sync unflushed WAL changes. See HBASE-8208 for details</div>
@@ -5021,7 +5021,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isAllFamilies</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2758">isAllFamilies</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;families)</pre>
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2761">isAllFamilies</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;families)</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>True if passed Set is all families in the region.</dd>
@@ -5034,7 +5034,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>writeFlushRequestMarkerToWAL</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2768">writeFlushRequestMarkerToWAL</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2771">writeFlushRequestMarkerToWAL</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                              boolean&nbsp;writeFlushWalMarker)</pre>
 <div class="block">Writes a marker to WAL indicating a flush is requested but cannot be complete due to various
  reasons. Ignores exceptions from WAL. Returns whether the write succeeded.</div>
@@ -5052,7 +5052,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>internalFlushCacheAndCommit</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2786">internalFlushCacheAndCommit</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.FlushResultImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2789">internalFlushCacheAndCommit</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                                               <a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status,
                                                               <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;prepareResult,
                                                               <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;storesToFlush)
@@ -5069,7 +5069,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getNextSequenceId</h4>
-<pre>protected&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2944">getNextSequenceId</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal)
+<pre>protected&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2947">getNextSequenceId</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Method to safely get the next sequence number.</div>
 <dl>
@@ -5086,7 +5086,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getScanner</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2955">getScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2958">getScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan)
                                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getScanner-org.apache.hadoop.hbase.client.Scan-">Region</a></code></span></div>
 <div class="block">Return an iterator that scans over the HRegion, returning the indicated
@@ -5111,7 +5111,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getScanner</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2960">getScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2963">getScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
                                             <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;additionalScanners)
                                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getScanner-org.apache.hadoop.hbase.client.Scan-java.util.List-">Region</a></code></span></div>
@@ -5140,7 +5140,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getScanner</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2965">getScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2968">getScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
                                              <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;additionalScanners,
                                              long&nbsp;nonceGroup,
                                              long&nbsp;nonce)
@@ -5157,7 +5157,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>instantiateRegionScanner</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">RegionScanner</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2986">instantiateRegionScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">RegionScanner</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2989">instantiateRegionScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
                                                  <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;additionalScanners)
                                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -5172,7 +5172,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>instantiateRegionScanner</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2992">instantiateRegionScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RegionScannerImpl</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.2995">instantiateRegionScanner</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan,
                                                              <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>&gt;&nbsp;additionalScanners,
                                                              long&nbsp;nonceGroup,
                                                              long&nbsp;nonce)
@@ -5189,7 +5189,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>prepareDelete</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3008">prepareDelete</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Delete.html" title="class in org.apache.hadoop.hbase.client">Delete</a>&nbsp;delete)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3011">prepareDelete</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Delete.html" title="class in org.apache.hadoop.hbase.client">Delete</a>&nbsp;delete)
                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Prepare a delete for a row mutation processor</div>
 <dl>
@@ -5206,7 +5206,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>delete</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3026">delete</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Delete.html" title="class in org.apache.hadoop.hbase.client">Delete</a>&nbsp;delete)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3029">delete</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Delete.html" title="class in org.apache.hadoop.hbase.client">Delete</a>&nbsp;delete)
             throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#delete-org.apache.hadoop.hbase.client.Delete-">Region</a></code></span></div>
 <div class="block">Deletes the specified cells/row.</div>
@@ -5224,7 +5224,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>delete</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3048">delete</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/NavigableMap.html?is-external=true" title="class or interface in java.util">NavigableMap</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3051">delete</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/NavigableMap.html?is-external=true" title="class or interface in java.util">NavigableMap</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
             <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;durability)
      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">This is used only by unit tests. Not required to be a public API.</div>
@@ -5242,7 +5242,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>prepareDeleteTimestamps</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3063">prepareDeleteTimestamps</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3066">prepareDeleteTimestamps</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
                                     <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
                                     byte[]&nbsp;byteNow)
                              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -5264,7 +5264,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>updateDeleteLatestVersionTimestamp</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3107">updateDeleteLatestVersionTimestamp</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3110">updateDeleteLatestVersionTimestamp</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell,
                                         <a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get,
                                         int&nbsp;count,
                                         byte[]&nbsp;byteNow)
@@ -5281,7 +5281,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>put</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3124">put</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;put)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.3127">put</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Put.html" title="class in org.apache.hadoop.hbase.client">Put</a>&nbsp;put)
          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#put-org.apache.hadoop.hbase.client.Put-">Region</a></code></span></div>
 <div class="block">Puts some data in the table.</div>
@@ -5299,7 +5299,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>batchMutate</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4000">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;mutations,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4003">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;mutations,
                                      long&nbsp;nonceGroup,
                                      long&nbsp;nonce)
                               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -5315,7 +5315,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>batchMutate</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4005">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;mutations,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4008">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;mutations,
                                      boolean&nbsp;atomic,
                                      long&nbsp;nonceGroup,
                                      long&nbsp;nonce)
@@ -5332,7 +5332,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>batchMutate</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4015">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;mutations)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4018">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>[]&nbsp;mutations)
                               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#batchMutate-org.apache.hadoop.hbase.client.Mutation:A-">Region</a></code></span></div>
 <div class="block">Perform a batch of mutations.
@@ -5357,7 +5357,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>batchReplay</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4019">batchReplay</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>[]&nbsp;mutations,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4022">batchReplay</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALSplitUtil.MutationReplay.html" title="class in org.apache.hadoop.hbase.wal">WALSplitUtil.MutationReplay</a>[]&nbsp;mutations,
                                      long&nbsp;replaySeqId)
                               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -5372,7 +5372,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>batchMutate</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4063">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;?&gt;&nbsp;batchOp)
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/OperationStatus.html" title="class in org.apache.hadoop.hbase.regionserver">OperationStatus</a>[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4066">batchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;?&gt;&nbsp;batchOp)
                        throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Perform a batch of mutations.
 
@@ -5404,7 +5404,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doMiniBatchMutate</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4094">doMiniBatchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;?&gt;&nbsp;batchOp)
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4097">doMiniBatchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.BatchOperation</a>&lt;?&gt;&nbsp;batchOp)
                         throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Called to do a piece of the batch that came in to <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html#batchMutate-org.apache.hadoop.hbase.client.Mutation:A-long-long-"><code>batchMutate(Mutation[], long, long)</code></a>
  In here we also handle replay of edits on region recover. Also gets change in size brought
@@ -5421,7 +5421,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getEffectiveDurability</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4182">getEffectiveDurability</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;d)</pre>
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4185">getEffectiveDurability</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;d)</pre>
 <div class="block">Returns effective durability from the passed durability and
  the table descriptor.</div>
 </li>
@@ -5432,7 +5432,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndMutate</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4187">checkAndMutate</a>(byte[]&nbsp;row,
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4190">checkAndMutate</a>(byte[]&nbsp;row,
                               byte[]&nbsp;family,
                               byte[]&nbsp;qualifier,
                               <a href="../../../../../org/apache/hadoop/hbase/CompareOperator.html" title="enum in org.apache.hadoop.hbase">CompareOperator</a>&nbsp;op,
@@ -5469,7 +5469,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkAndRowMutate</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4194">checkAndRowMutate</a>(byte[]&nbsp;row,
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4197">checkAndRowMutate</a>(byte[]&nbsp;row,
                                  byte[]&nbsp;family,
                                  byte[]&nbsp;qualifier,
                                  <a href="../../../../../org/apache/hadoop/hbase/CompareOperator.html" title="enum in org.apache.hadoop.hbase">CompareOperator</a>&nbsp;op,
@@ -5506,7 +5506,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doCheckAndRowMutate</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4203">doCheckAndRowMutate</a>(byte[]&nbsp;row,
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4206">doCheckAndRowMutate</a>(byte[]&nbsp;row,
                                     byte[]&nbsp;family,
                                     byte[]&nbsp;qualifier,
                                     <a href="../../../../../org/apache/hadoop/hbase/CompareOperator.html" title="enum in org.apache.hadoop.hbase">CompareOperator</a>&nbsp;op,
@@ -5529,7 +5529,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkMutationType</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4302">checkMutationType</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4305">checkMutationType</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
                                byte[]&nbsp;row)
                         throws <a href="../../../../../org/apache/hadoop/hbase/DoNotRetryIOException.html" title="class in org.apache.hadoop.hbase">DoNotRetryIOException</a></pre>
 <dl>
@@ -5544,7 +5544,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>matches</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4313">matches</a>(<a href="../../../../../org/apache/hadoop/hbase/CompareOperator.html" title="enum in org.apache.hadoop.hbase">CompareOperator</a>&nbsp;op,
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4316">matches</a>(<a href="../../../../../org/apache/hadoop/hbase/CompareOperator.html" title="enum in org.apache.hadoop.hbase">CompareOperator</a>&nbsp;op,
                         int&nbsp;compareResult)</pre>
 </li>
 </ul>
@@ -5554,7 +5554,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doBatchMutate</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4341">doBatchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation)
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4344">doBatchMutate</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation)
                     throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -5568,7 +5568,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>addRegionToSnapshot</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4366">addRegionToSnapshot</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription&nbsp;desc,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4369">addRegionToSnapshot</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription&nbsp;desc,
                                 <a href="../../../../../org/apache/hadoop/hbase/errorhandling/ForeignExceptionSnare.html" title="interface in org.apache.hadoop.hbase.errorhandling">ForeignExceptionSnare</a>&nbsp;exnSnare)
                          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Complete taking the snapshot on the region. Writes the region info and adds references to the
@@ -5593,7 +5593,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>updateSequenceId</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4376">updateSequenceId</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html?is-external=true" title="class or interface in java.lang">Iterable</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;cellItr,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4379">updateSequenceId</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html?is-external=true" title="class or interface in java.lang">Iterable</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;cellItr,
                               long&nbsp;sequenceId)
                        throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -5608,7 +5608,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>updateCellTimestamps</h4>
-<pre>private static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4392">updateCellTimestamps</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html?is-external=true" title="class or interface in java.lang">Iterable</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;cellItr,
+<pre>private static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4395">updateCellTimestamps</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html?is-external=true" title="class or interface in java.lang">Iterable</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;cellItr,
                                          byte[]&nbsp;now)
                                   throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Replace any cell timestamps set to <a href="../../../../../org/apache/hadoop/hbase/HConstants.html#LATEST_TIMESTAMP"><code>HConstants.LATEST_TIMESTAMP</code></a>
@@ -5628,7 +5628,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>rewriteCellTags</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4409">rewriteCellTags</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4412">rewriteCellTags</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
                      <a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;m)</pre>
 <div class="block">Possibly rewrite incoming cell tags.</div>
 </li>
@@ -5639,7 +5639,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkResources</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4437">checkResources</a>()
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4440">checkResources</a>()
              throws <a href="../../../../../org/apache/hadoop/hbase/RegionTooBusyException.html" title="class in org.apache.hadoop.hbase">RegionTooBusyException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -5653,7 +5653,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkReadOnly</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4459">checkReadOnly</a>()
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4462">checkReadOnly</a>()
                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -5667,7 +5667,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkReadsEnabled</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4465">checkReadsEnabled</a>()
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4468">checkReadsEnabled</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -5681,7 +5681,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setReadsEnabled</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4472">setReadsEnabled</a>(boolean&nbsp;readsEnabled)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4475">setReadsEnabled</a>(boolean&nbsp;readsEnabled)</pre>
 </li>
 </ul>
 <a name="put-byte:A-byte:A-java.util.List-">
@@ -5690,7 +5690,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>put</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4485">put</a>(byte[]&nbsp;row,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4488">put</a>(byte[]&nbsp;row,
          byte[]&nbsp;family,
          <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;edits)
   throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -5711,7 +5711,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>applyToMemStore</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4500">applyToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4503">applyToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
                              <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;cells,
                              boolean&nbsp;delta,
                              <a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSizing.html" title="interface in org.apache.hadoop.hbase.regionserver">MemStoreSizing</a>&nbsp;memstoreAccounting)
@@ -5734,7 +5734,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>applyToMemStore</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4514">applyToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4517">applyToMemStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
                              <a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell,
                              <a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSizing.html" title="interface in org.apache.hadoop.hbase.regionserver">MemStoreSizing</a>&nbsp;memstoreAccounting)
                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -5752,7 +5752,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkFamilies</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4524">checkFamilies</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;byte[]&gt;&nbsp;families,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4527">checkFamilies</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;byte[]&gt;&nbsp;families,
                            <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;durability)
                     throws <a href="../../../../../org/apache/hadoop/hbase/regionserver/NoSuchColumnFamilyException.html" title="class in org.apache.hadoop.hbase.regionserver">NoSuchColumnFamilyException</a>,
                            <a href="../../../../../org/apache/hadoop/hbase/regionserver/InvalidMutationDurabilityException.html" title="class in org.apache.hadoop.hbase.regionserver">InvalidMutationDurabilityException</a></pre>
@@ -5769,7 +5769,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkFamily</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4531">checkFamily</a>(byte[]&nbsp;family,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4534">checkFamily</a>(byte[]&nbsp;family,
                          <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;durability)
                   throws <a href="../../../../../org/apache/hadoop/hbase/regionserver/NoSuchColumnFamilyException.html" title="class in org.apache.hadoop.hbase.regionserver">NoSuchColumnFamilyException</a>,
                          <a href="../../../../../org/apache/hadoop/hbase/regionserver/InvalidMutationDurabilityException.html" title="class in org.apache.hadoop.hbase.regionserver">InvalidMutationDurabilityException</a></pre>
@@ -5786,7 +5786,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkFamily</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4543">checkFamily</a>(byte[]&nbsp;family)
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4546">checkFamily</a>(byte[]&nbsp;family)
           throws <a href="../../../../../org/apache/hadoop/hbase/regionserver/NoSuchColumnFamilyException.html" title="class in org.apache.hadoop.hbase.regionserver">NoSuchColumnFamilyException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -5800,7 +5800,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkTimestamps</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4557">checkTimestamps</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4560">checkTimestamps</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap,
                             long&nbsp;now)
                      throws <a href="../../../../../org/apache/hadoop/hbase/exceptions/FailedSanityCheckException.html" title="class in org.apache.hadoop.hbase.exceptions">FailedSanityCheckException</a></pre>
 <div class="block">Check the collection of families for valid timestamps</div>
@@ -5819,7 +5819,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isFlushSize</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4584">isFlushSize</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;size)</pre>
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4587">isFlushSize</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;size)</pre>
 </li>
 </ul>
 <a name="replayRecoveredEditsIfAny-java.util.Map-org.apache.hadoop.hbase.util.CancelableProgressable-org.apache.hadoop.hbase.monitoring.MonitoredTask-">
@@ -5828,7 +5828,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayRecoveredEditsIfAny</h4>
-<pre>protected&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4621">replayRecoveredEditsIfAny</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html?is-external=true" title="class or interface in java.lang">Long</a>&gt;&nbsp;maxSeqIdInStores,
+<pre>protected&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4624">replayRecoveredEditsIfAny</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html?is-external=true" title="class or interface in java.lang">Long</a>&gt;&nbsp;maxSeqIdInStores,
                                          <a href="../../../../../org/apache/hadoop/hbase/util/CancelableProgressable.html" title="interface in org.apache.hadoop.hbase.util">CancelableProgressable</a>&nbsp;reporter,
                                          <a href="../../../../../org/apache/hadoop/hbase/monitoring/MonitoredTask.html" title="interface in org.apache.hadoop.hbase.monitoring">MonitoredTask</a>&nbsp;status)
                                   throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -5875,7 +5875,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayRecoveredEditsForPaths</h4>
-<pre>private&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4691">replayRecoveredEditsForPaths</a>(long&nbsp;minSeqIdForTheRegion,
+<pre>private&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4694">replayRecoveredEditsForPaths</a>(long&nbsp;minSeqIdForTheRegion,
                                           org.apache.hadoop.fs.FileSystem&nbsp;fs,
                                           <a href="https://docs.oracle.com/javase/8/docs/api/java/util/NavigableSet.html?is-external=true" title="class or interface in java.util">NavigableSet</a>&lt;org.apache.hadoop.fs.Path&gt;&nbsp;files,
                                           <a href="../../../../../org/apache/hadoop/hbase/util/CancelableProgressable.html" title="interface in org.apache.hadoop.hbase.util">CancelableProgressable</a>&nbsp;reporter,
@@ -5893,7 +5893,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayRecoveredEdits</h4>
-<pre>private&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4761">replayRecoveredEdits</a>(org.apache.hadoop.fs.Path&nbsp;edits,
+<pre>private&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4764">replayRecoveredEdits</a>(org.apache.hadoop.fs.Path&nbsp;edits,
                                   <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html?is-external=true" title="class or interface in java.lang">Long</a>&gt;&nbsp;maxSeqIdInStores,
                                   <a href="../../../../../org/apache/hadoop/hbase/util/CancelableProgressable.html" title="interface in org.apache.hadoop.hbase.util">CancelableProgressable</a>&nbsp;reporter,
                                   org.apache.hadoop.fs.FileSystem&nbsp;fs)
@@ -5910,7 +5910,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALCompactionMarker</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4964">replayWALCompactionMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.CompactionDescriptor&nbsp;compaction,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.4967">replayWALCompactionMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.CompactionDescriptor&nbsp;compaction,
                                boolean&nbsp;pickCompactionFiles,
                                boolean&nbsp;removeFiles,
                                long&nbsp;replaySeqId)
@@ -5930,7 +5930,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALFlushMarker</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5025">replayWALFlushMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5028">replayWALFlushMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush,
                           long&nbsp;replaySeqId)
                    throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -5945,7 +5945,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALFlushStartMarker</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5072">replayWALFlushStartMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush)
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5075">replayWALFlushStartMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush)
                                               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Replay the flush marker from primary region by creating a corresponding snapshot of
  the store memstores, only if the memstores do not have a higher seqId from an earlier wal
@@ -5962,7 +5962,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALFlushCommitMarker</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5185">replayWALFlushCommitMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush)
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5188">replayWALFlushCommitMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush)
                          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -5976,7 +5976,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayFlushInStores</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5309">replayFlushInStores</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5312">replayFlushInStores</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush,
                                  <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;prepareFlushResult,
                                  boolean&nbsp;dropMemstoreSnapshot)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -5998,7 +5998,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>dropMemStoreContents</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5350">dropMemStoreContents</a>()
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5353">dropMemStoreContents</a>()
                                   throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Be careful, this method will drop all data in the memstore of this region.
  Currently, this method is used to drop memstore to prevent memory leak
@@ -6015,7 +6015,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>dropMemStoreContentsForSeqId</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5372">dropMemStoreContentsForSeqId</a>(long&nbsp;seqId,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5375">dropMemStoreContentsForSeqId</a>(long&nbsp;seqId,
                                                   <a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store)
                                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Drops the memstore contents after replaying a flush descriptor or region open event replay
@@ -6032,7 +6032,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doDropStoreMemStoreContentsForSeqId</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5403">doDropStoreMemStoreContentsForSeqId</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;s,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSize.html" title="class in org.apache.hadoop.hbase.regionserver">MemStoreSize</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5406">doDropStoreMemStoreContentsForSeqId</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;s,
                                                          long&nbsp;currentSeqId)
                                                   throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -6047,7 +6047,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALFlushAbortMarker</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5413">replayWALFlushAbortMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush)</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5416">replayWALFlushAbortMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush)</pre>
 </li>
 </ul>
 <a name="replayWALFlushCannotFlushMarker-org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor-long-">
@@ -6056,7 +6056,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALFlushCannotFlushMarker</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5419">replayWALFlushCannotFlushMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5422">replayWALFlushCannotFlushMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor&nbsp;flush,
                                              long&nbsp;replaySeqId)</pre>
 </li>
 </ul>
@@ -6066,7 +6066,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getPrepareFlushResult</h4>
-<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5439">getPrepareFlushResult</a>()</pre>
+<pre><a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.PrepareFlushResult</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5442">getPrepareFlushResult</a>()</pre>
 </li>
 </ul>
 <a name="replayWALRegionEventMarker-org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.RegionEventDescriptor-">
@@ -6075,7 +6075,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALRegionEventMarker</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5445">replayWALRegionEventMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.RegionEventDescriptor&nbsp;regionEvent)
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5448">replayWALRegionEventMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.RegionEventDescriptor&nbsp;regionEvent)
                          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -6089,7 +6089,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>replayWALBulkLoadEventMarker</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5561">replayWALBulkLoadEventMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.BulkLoadDescriptor&nbsp;bulkLoadEvent)
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5564">replayWALBulkLoadEventMarker</a>(org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.BulkLoadDescriptor&nbsp;bulkLoadEvent)
                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -6103,7 +6103,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>dropPrepareFlushIfPossible</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5644">dropPrepareFlushIfPossible</a>()</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5647">dropPrepareFlushIfPossible</a>()</pre>
 <div class="block">If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult</div>
 </li>
 </ul>
@@ -6113,7 +6113,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>refreshStoreFiles</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5671">refreshStoreFiles</a>()
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5674">refreshStoreFiles</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#refreshStoreFiles--">Region</a></code></span></div>
 <div class="block">Check the region's underlying store files, open the files that have not
@@ -6133,7 +6133,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>refreshStoreFiles</h4>
-<pre>protected&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5677">refreshStoreFiles</a>(boolean&nbsp;force)
+<pre>protected&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5680">refreshStoreFiles</a>(boolean&nbsp;force)
                              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -6147,7 +6147,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>logRegionFiles</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5768">logRegionFiles</a>()</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5771">logRegionFiles</a>()</pre>
 </li>
 </ul>
 <a name="checkTargetRegion-byte:A-java.lang.String-java.lang.Object-">
@@ -6156,7 +6156,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkTargetRegion</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5780">checkTargetRegion</a>(byte[]&nbsp;encodedRegionName,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5783">checkTargetRegion</a>(byte[]&nbsp;encodedRegionName,
                                <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;exceptionMsg,
                                <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;payload)
                         throws <a href="../../../../../org/apache/hadoop/hbase/regionserver/WrongRegionException.html" title="class in org.apache.hadoop.hbase.regionserver">WrongRegionException</a></pre>
@@ -6174,7 +6174,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>restoreEdit</h4>
-<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5803">restoreEdit</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;s,
+<pre>protected&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5806">restoreEdit</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;s,
                            <a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell,
                            <a href="../../../../../org/apache/hadoop/hbase/regionserver/MemStoreSizing.html" title="interface in org.apache.hadoop.hbase.regionserver">MemStoreSizing</a>&nbsp;memstoreAccounting)</pre>
 <div class="block">Used by tests</div>
@@ -6191,7 +6191,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>isZeroLengthThenDelete</h4>
-<pre>private static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5812">isZeroLengthThenDelete</a>(org.apache.hadoop.fs.FileSystem&nbsp;fs,
+<pre>private static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5815">isZeroLengthThenDelete</a>(org.apache.hadoop.fs.FileSystem&nbsp;fs,
                                               org.apache.hadoop.fs.Path&nbsp;p)
                                        throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -6210,7 +6210,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>instantiateHStore</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5823">instantiateHStore</a>(<a href="../../../../../org/apache/hadoop/hbase/client/ColumnFamilyDescriptor.html" title="interface in org.apache.hadoop.hbase.client">ColumnFamilyDescriptor</a>&nbsp;family,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5826">instantiateHStore</a>(<a href="../../../../../org/apache/hadoop/hbase/client/ColumnFamilyDescriptor.html" title="interface in org.apache.hadoop.hbase.client">ColumnFamilyDescriptor</a>&nbsp;family,
                                    boolean&nbsp;warmup)
                             throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -6225,7 +6225,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStore</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5837">getStore</a>(byte[]&nbsp;column)</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5840">getStore</a>(byte[]&nbsp;column)</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getStore-byte:A-">Region</a></code></span></div>
 <div class="block">Return the Store for the given family
  <p>Use with caution.  Exposed for use of fixup utilities.</div>
@@ -6243,7 +6243,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStore</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5845">getStore</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell)</pre>
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5848">getStore</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell)</pre>
 <div class="block">Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on
  the list.</div>
 </li>
@@ -6254,7 +6254,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStores</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5851">getStores</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5854">getStores</a>()</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getStores--">Region</a></code></span></div>
 <div class="block">Return the list of Stores managed by this region
  <p>Use with caution.  Exposed for use of fixup utilities.</div>
@@ -6272,7 +6272,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStoreFileList</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5856">getStoreFileList</a>(byte[][]&nbsp;columns)
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5859">getStoreFileList</a>(byte[][]&nbsp;columns)
                               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalArgumentException.html?is-external=true" title="class or interface in java.lang">IllegalArgumentException</a></pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -6290,7 +6290,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkRow</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5884">checkRow</a>(byte[]&nbsp;row,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5887">checkRow</a>(byte[]&nbsp;row,
               <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;op)
        throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Make sure this is a valid row for the HRegion</div>
@@ -6306,7 +6306,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRowLock</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5901">getRowLock</a>(byte[]&nbsp;row)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5904">getRowLock</a>(byte[]&nbsp;row)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Get an exclusive ( write lock ) lock on a given row.</div>
 <dl>
@@ -6325,7 +6325,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRowLock</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5906">getRowLock</a>(byte[]&nbsp;row,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5909">getRowLock</a>(byte[]&nbsp;row,
                                  boolean&nbsp;readLock)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getRowLock-byte:A-boolean-">Region</a></code></span></div>
@@ -6360,7 +6360,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRowLockInternal</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5911">getRowLockInternal</a>(byte[]&nbsp;row,
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5914">getRowLockInternal</a>(byte[]&nbsp;row,
                                             boolean&nbsp;readLock,
                                             <a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&nbsp;prevRowLock)
                                      throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -6376,7 +6376,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>releaseRowLocks</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5995">releaseRowLocks</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;rowLocks)</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.5998">releaseRowLocks</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.RowLock.html" title="interface in org.apache.hadoop.hbase.regionserver">Region.RowLock</a>&gt;&nbsp;rowLocks)</pre>
 </li>
 </ul>
 <a name="getReadLockCount--">
@@ -6385,7 +6385,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getReadLockCount</h4>
-<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6005">getReadLockCount</a>()</pre>
+<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6008">getReadLockCount</a>()</pre>
 </li>
 </ul>
 <a name="getLockedRows--">
@@ -6394,7 +6394,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getLockedRows</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html?is-external=true" title="class or interface in java.util.concurrent">ConcurrentHashMap</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/HashedBytes.html" title="class in org.apache.hadoop.hbase.util">HashedBytes</a>,<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6009">getLockedRows</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html?is-external=true" title="class or interface in java.util.concurrent">ConcurrentHashMap</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/HashedBytes.html" title="class in org.apache.hadoop.hbase.util">HashedBytes</a>,<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion.RowLockContext</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6012">getLockedRows</a>()</pre>
 </li>
 </ul>
 <a name="hasMultipleColumnFamilies-java.util.Collection-">
@@ -6403,7 +6403,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>hasMultipleColumnFamilies</h4>
-<pre>private static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6116">hasMultipleColumnFamilies</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&gt;&nbsp;familyPaths)</pre>
+<pre>private static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6119">hasMultipleColumnFamilies</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&gt;&nbsp;familyPaths)</pre>
 <div class="block">Determines whether multiple column families are present
  Precondition: familyPaths is not null</div>
 <dl>
@@ -6418,7 +6418,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>bulkLoadHFiles</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;org.apache.hadoop.fs.Path&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6142">bulkLoadHFiles</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&gt;&nbsp;familyPaths,
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;org.apache.hadoop.fs.Path&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6145">bulkLoadHFiles</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&gt;&nbsp;familyPaths,
                                                                   boolean&nbsp;assignSeqId,
                                                                   <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html" title="interface in org.apache.hadoop.hbase.regionserver">HRegion.BulkLoadListener</a>&nbsp;bulkLoadListener)
                                                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -6443,7 +6443,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>bulkLoadHFiles</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;org.apache.hadoop.fs.Path&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6192">bulkLoadHFiles</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&gt;&nbsp;familyPaths,
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;org.apache.hadoop.fs.Path&gt;&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6195">bulkLoadHFiles</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/util/Pair.html" title="class in org.apache.hadoop.hbase.util">Pair</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&gt;&nbsp;familyPaths,
                                                                   boolean&nbsp;assignSeqId,
                                                                   <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html" title="interface in org.apache.hadoop.hbase.regionserver">HRegion.BulkLoadListener</a>&nbsp;bulkLoadListener,
                                                                   boolean&nbsp;copyFile)
@@ -6470,7 +6470,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>equals</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6388">equals</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;o)</pre>
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6391">equals</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;o)</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Overrides:</span></dt>
 <dd><code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true#equals-java.lang.Object-" title="class or interface in java.lang">equals</a></code>&nbsp;in class&nbsp;<code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></code></dd>
@@ -6483,7 +6483,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>hashCode</h4>
-<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6394">hashCode</a>()</pre>
+<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6397">hashCode</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Overrides:</span></dt>
 <dd><code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true#hashCode--" title="class or interface in java.lang">hashCode</a></code>&nbsp;in class&nbsp;<code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></code></dd>
@@ -6496,7 +6496,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>toString</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6399">toString</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.6402">toString</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Overrides:</span></dt>
 <dd><code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true#toString--" title="class or interface in java.lang">toString</a></code>&nbsp;in class&nbsp;<code><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></code></dd>
@@ -6509,7 +6509,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>newHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7094">newHRegion</a>(org.apache.hadoop.fs.Path&nbsp;tableDir,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7097">newHRegion</a>(org.apache.hadoop.fs.Path&nbsp;tableDir,
                                  <a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                  org.apache.hadoop.fs.FileSystem&nbsp;fs,
                                  org.apache.hadoop.conf.Configuration&nbsp;conf,
@@ -6544,7 +6544,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>createHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7124">createHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7127">createHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                     org.apache.hadoop.fs.Path&nbsp;rootDir,
                                     org.apache.hadoop.conf.Configuration&nbsp;conf,
                                     <a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;hTableDescriptor,
@@ -6571,7 +6571,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>createRegionDir</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegionFileSystem.html" title="class in org.apache.hadoop.hbase.regionserver">HRegionFileSystem</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7144">createRegionDir</a>(org.apache.hadoop.conf.Configuration&nbsp;configuration,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegionFileSystem.html" title="class in org.apache.hadoop.hbase.regionserver">HRegionFileSystem</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7147">createRegionDir</a>(org.apache.hadoop.conf.Configuration&nbsp;configuration,
                                                 <a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;ri,
                                                 org.apache.hadoop.fs.Path&nbsp;rootDir)
                                          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -6588,7 +6588,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>createHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7154">createHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7157">createHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                     org.apache.hadoop.fs.Path&nbsp;rootDir,
                                     org.apache.hadoop.conf.Configuration&nbsp;conf,
                                     <a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;hTableDescriptor,
@@ -6606,7 +6606,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7174">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7177">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;htd,
                                   <a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                   org.apache.hadoop.conf.Configuration&nbsp;conf)
@@ -6632,7 +6632,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7196">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7199">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;htd,
                                   <a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                   org.apache.hadoop.conf.Configuration&nbsp;conf,
@@ -6664,7 +6664,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7217">openHRegion</a>(org.apache.hadoop.fs.Path&nbsp;rootDir,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7220">openHRegion</a>(org.apache.hadoop.fs.Path&nbsp;rootDir,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;htd,
                                   <a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
@@ -6694,7 +6694,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7238">openHRegion</a>(org.apache.hadoop.fs.Path&nbsp;rootDir,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7241">openHRegion</a>(org.apache.hadoop.fs.Path&nbsp;rootDir,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;htd,
                                   <a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
@@ -6728,7 +6728,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7266">openHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7269">openHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
                                   org.apache.hadoop.fs.FileSystem&nbsp;fs,
                                   org.apache.hadoop.fs.Path&nbsp;rootDir,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
@@ -6760,7 +6760,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7287">openHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7290">openHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
                                   org.apache.hadoop.fs.FileSystem&nbsp;fs,
                                   org.apache.hadoop.fs.Path&nbsp;rootDir,
                                   <a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
@@ -6796,7 +6796,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7310">openHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7313">openHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
                                   org.apache.hadoop.fs.FileSystem&nbsp;fs,
                                   org.apache.hadoop.fs.Path&nbsp;rootDir,
                                   org.apache.hadoop.fs.Path&nbsp;tableDir,
@@ -6833,7 +6833,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getReplicationScope</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/NavigableMap.html?is-external=true" title="class or interface in java.util">NavigableMap</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html?is-external=true" title="class or interface in java.lang">Integer</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7324">getReplicationScope</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/NavigableMap.html?is-external=true" title="class or interface in java.util">NavigableMap</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html?is-external=true" title="class or interface in java.lang">Integer</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7327">getReplicationScope</a>()</pre>
 </li>
 </ul>
 <a name="openHRegion-org.apache.hadoop.hbase.regionserver.HRegion-org.apache.hadoop.hbase.util.CancelableProgressable-">
@@ -6842,7 +6842,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7334">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;other,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7337">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;other,
                                   <a href="../../../../../org/apache/hadoop/hbase/util/CancelableProgressable.html" title="interface in org.apache.hadoop.hbase.util">CancelableProgressable</a>&nbsp;reporter)
                            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Useful when reopening a closed region (normally for unit tests)</div>
@@ -6863,7 +6863,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7342">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a>&nbsp;other,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7345">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a>&nbsp;other,
                                  <a href="../../../../../org/apache/hadoop/hbase/util/CancelableProgressable.html" title="interface in org.apache.hadoop.hbase.util">CancelableProgressable</a>&nbsp;reporter)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -6878,7 +6878,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openHRegion</h4>
-<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7352">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/util/CancelableProgressable.html" title="interface in org.apache.hadoop.hbase.util">CancelableProgressable</a>&nbsp;reporter)
+<pre>protected&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7355">openHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/util/CancelableProgressable.html" title="interface in org.apache.hadoop.hbase.util">CancelableProgressable</a>&nbsp;reporter)
                        throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Open HRegion.
  Calls initialize and sets sequenceId.</div>
@@ -6896,7 +6896,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>openReadOnlyFileSystemHRegion</h4>
-<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7391">openReadOnlyFileSystemHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
+<pre>public static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7394">openReadOnlyFileSystemHRegion</a>(org.apache.hadoop.conf.Configuration&nbsp;conf,
                                                     org.apache.hadoop.fs.FileSystem&nbsp;fs,
                                                     org.apache.hadoop.fs.Path&nbsp;tableDir,
                                                     <a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
@@ -6922,7 +6922,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>warmupHRegion</h4>
-<pre>public static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7407">warmupHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
+<pre>public static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7410">warmupHRegion</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                  <a href="../../../../../org/apache/hadoop/hbase/client/TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a>&nbsp;htd,
                                  <a href="../../../../../org/apache/hadoop/hbase/wal/WAL.html" title="interface in org.apache.hadoop.hbase.wal">WAL</a>&nbsp;wal,
                                  org.apache.hadoop.conf.Configuration&nbsp;conf,
@@ -6941,7 +6941,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkCompressionCodecs</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7435">checkCompressionCodecs</a>()
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7438">checkCompressionCodecs</a>()
                              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -6955,7 +6955,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkEncryption</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7442">checkEncryption</a>()
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7445">checkEncryption</a>()
                       throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -6969,7 +6969,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkClassLoading</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7448">checkClassLoading</a>()
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7451">checkClassLoading</a>()
                         throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -6984,7 +6984,7 @@
 <li class="blockList">
 <h4>getRegionDir</h4>
 <pre><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Deprecated.html?is-external=true" title="class or interface in java.lang">@Deprecated</a>
-public static&nbsp;org.apache.hadoop.fs.Path&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7462">getRegionDir</a>(org.apache.hadoop.fs.Path&nbsp;tabledir,
+public static&nbsp;org.apache.hadoop.fs.Path&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7465">getRegionDir</a>(org.apache.hadoop.fs.Path&nbsp;tabledir,
                                                                  <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;name)</pre>
 <div class="block"><span class="deprecatedLabel">Deprecated.</span>&nbsp;<span class="deprecationComment">For tests only; to be removed.</span></div>
 <div class="block">Computes the Path of the HRegion</div>
@@ -7003,7 +7003,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>rowIsInRange</h4>
-<pre>public static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7474">rowIsInRange</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
+<pre>public static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7477">rowIsInRange</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                    byte[]&nbsp;row)</pre>
 <div class="block">Determines if the specified row is within the row range specified by the
  specified RegionInfo</div>
@@ -7022,7 +7022,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>rowIsInRange</h4>
-<pre>public static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7481">rowIsInRange</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
+<pre>public static&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7484">rowIsInRange</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;info,
                                    byte[]&nbsp;row,
                                    int&nbsp;offset,
                                    short&nbsp;length)</pre>
@@ -7034,7 +7034,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>get</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7491">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7494">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get)
            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#get-org.apache.hadoop.hbase.client.Get-">Region</a></code></span></div>
 <div class="block">Do a get based on the get parameter.</div>
@@ -7056,7 +7056,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>prepareGet</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7498">prepareGet</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get)
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7501">prepareGet</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get)
          throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -7070,7 +7070,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>get</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7513">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get,
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7516">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get,
                       boolean&nbsp;withCoprocessor)
                throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#get-org.apache.hadoop.hbase.client.Get-boolean-">Region</a></code></span></div>
@@ -7095,7 +7095,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>get</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7517">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get,
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7520">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Get.html" title="class in org.apache.hadoop.hbase.client">Get</a>&nbsp;get,
                       boolean&nbsp;withCoprocessor,
                       long&nbsp;nonceGroup,
                       long&nbsp;nonce)
@@ -7112,7 +7112,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>metricsUpdateForGet</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7552">metricsUpdateForGet</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7555">metricsUpdateForGet</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;results,
                          long&nbsp;before)</pre>
 </li>
 </ul>
@@ -7122,7 +7122,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>mutateRow</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7559">mutateRow</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RowMutations.html" title="class in org.apache.hadoop.hbase.client">RowMutations</a>&nbsp;rm)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7562">mutateRow</a>(<a href="../../../../../org/apache/hadoop/hbase/client/RowMutations.html" title="class in org.apache.hadoop.hbase.client">RowMutations</a>&nbsp;rm)
                throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#mutateRow-org.apache.hadoop.hbase.client.RowMutations-">Region</a></code></span></div>
 <div class="block">Performs multiple mutations atomically on a single row. Currently
@@ -7143,7 +7143,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>mutateRowsWithLocks</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7579">mutateRowsWithLocks</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;mutations,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7582">mutateRowsWithLocks</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;mutations,
                                 <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;byte[]&gt;&nbsp;rowsToLock,
                                 long&nbsp;nonceGroup,
                                 long&nbsp;nonce)
@@ -7172,7 +7172,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getLoadStatistics</h4>
-<pre>public&nbsp;org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.RegionLoadStats&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7607">getLoadStatistics</a>()</pre>
+<pre>public&nbsp;org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.RegionLoadStats&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7610">getLoadStatistics</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>statistics about the current load of the region</dd>
@@ -7185,7 +7185,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>processRowsWithLocks</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7630">processRowsWithLocks</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7633">processRowsWithLocks</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#processRowsWithLocks-org.apache.hadoop.hbase.regionserver.RowProcessor-">Region</a></code></span></div>
 <div class="block">Performs atomic multiple reads and writes on a given row.</div>
@@ -7205,7 +7205,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>processRowsWithLocks</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7635">processRowsWithLocks</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7638">processRowsWithLocks</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
                                  long&nbsp;nonceGroup,
                                  long&nbsp;nonce)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -7229,7 +7229,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>processRowsWithLocks</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7641">processRowsWithLocks</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7644">processRowsWithLocks</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
                                  long&nbsp;timeout,
                                  long&nbsp;nonceGroup,
                                  long&nbsp;nonce)
@@ -7256,7 +7256,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>preProcess</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7766">preProcess</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7769">preProcess</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
                         <a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit)
                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <dl>
@@ -7271,7 +7271,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doProcessRowWithTimeout</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7776">doProcessRowWithTimeout</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7779">doProcessRowWithTimeout</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RowProcessor.html" title="interface in org.apache.hadoop.hbase.regionserver">RowProcessor</a>&lt;?,?&gt;&nbsp;processor,
                                      long&nbsp;now,
                                      <a href="../../../../../org/apache/hadoop/hbase/regionserver/HRegion.html" title="class in org.apache.hadoop.hbase.regionserver">HRegion</a>&nbsp;region,
                                      <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&gt;&nbsp;mutations,
@@ -7290,7 +7290,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>append</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7826">append</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Append.html" title="class in org.apache.hadoop.hbase.client">Append</a>&nbsp;append)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7829">append</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Append.html" title="class in org.apache.hadoop.hbase.client">Append</a>&nbsp;append)
               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#append-org.apache.hadoop.hbase.client.Append-">Region</a></code></span></div>
 <div class="block">Perform one or more append operations on a row.</div>
@@ -7310,7 +7310,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>append</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7830">append</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Append.html" title="class in org.apache.hadoop.hbase.client">Append</a>&nbsp;mutation,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7833">append</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Append.html" title="class in org.apache.hadoop.hbase.client">Append</a>&nbsp;mutation,
                      long&nbsp;nonceGroup,
                      long&nbsp;nonce)
               throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -7326,7 +7326,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>increment</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7835">increment</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Increment.html" title="class in org.apache.hadoop.hbase.client">Increment</a>&nbsp;increment)
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7838">increment</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Increment.html" title="class in org.apache.hadoop.hbase.client">Increment</a>&nbsp;increment)
                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#increment-org.apache.hadoop.hbase.client.Increment-">Region</a></code></span></div>
 <div class="block">Perform one or more increment operations on a row.</div>
@@ -7346,7 +7346,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>increment</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7839">increment</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Increment.html" title="class in org.apache.hadoop.hbase.client">Increment</a>&nbsp;mutation,
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7842">increment</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Increment.html" title="class in org.apache.hadoop.hbase.client">Increment</a>&nbsp;mutation,
                         long&nbsp;nonceGroup,
                         long&nbsp;nonce)
                  throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
@@ -7362,7 +7362,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doDelta</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7853">doDelta</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7856">doDelta</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op,
                        <a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
                        long&nbsp;nonceGroup,
                        long&nbsp;nonce,
@@ -7388,7 +7388,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doWALAppend</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7932">doWALAppend</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7935">doWALAppend</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
                                                               <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;durability,
                                                               long&nbsp;nonceGroup,
                                                               long&nbsp;nonce)
@@ -7405,7 +7405,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doWALAppend</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7939">doWALAppend</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7942">doWALAppend</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
                                                               <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;durability,
                                                               <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html?is-external=true" title="class or interface in java.util">UUID</a>&gt;&nbsp;clusterIds,
                                                               long&nbsp;now,
@@ -7424,7 +7424,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doWALAppend</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7948">doWALAppend</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/MultiVersionConcurrencyControl.WriteEntry.html" title="class in org.apache.hadoop.hbase.regionserver">MultiVersionConcurrencyControl.WriteEntry</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7951">doWALAppend</a>(<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;walEdit,
                                                               <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;durability,
                                                               <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html?is-external=true" title="class or interface in java.util">UUID</a>&gt;&nbsp;clusterIds,
                                                               long&nbsp;now,
@@ -7446,7 +7446,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>doCoprocessorPreCall</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7994">doCoprocessorPreCall</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/Result.html" title="class in org.apache.hadoop.hbase.client">Result</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.7997">doCoprocessorPreCall</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op,
                                     <a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation)
                              throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Do coprocessor pre-increment or pre-append call.</div>
@@ -7465,7 +7465,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>reckonDeltas</h4>
-<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8020">reckonDeltas</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op,
+<pre>private&nbsp;<a href="../../../../../org/apache/hadoop/hbase/wal/WALEdit.html" title="class in org.apache.hadoop.hbase.wal">WALEdit</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8023">reckonDeltas</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op,
                              <a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
                              <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;effectiveDurability,
                              <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>,<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;forMemStore,
@@ -7491,7 +7491,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>reckonDeltasByStore</h4>
-<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8066">reckonDeltasByStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
+<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8069">reckonDeltasByStore</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
                                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op,
                                        <a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
                                        <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;effectiveDurability,
@@ -7524,7 +7524,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>reckonDelta</h4>
-<pre>private static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8142">reckonDelta</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;delta,
+<pre>private static&nbsp;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8145">reckonDelta</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;delta,
                                 <a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;currentCell,
                                 byte[]&nbsp;columnFamily,
                                 long&nbsp;now,
@@ -7543,7 +7543,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getLongValue</h4>
-<pre>private static&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8170">getLongValue</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell)
+<pre>private static&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8173">getLongValue</a>(<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&nbsp;cell)
                           throws <a href="../../../../../org/apache/hadoop/hbase/DoNotRetryIOException.html" title="class in org.apache.hadoop.hbase">DoNotRetryIOException</a></pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
@@ -7559,7 +7559,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>get</h4>
-<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8186">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
+<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8189">get</a>(<a href="../../../../../org/apache/hadoop/hbase/client/Mutation.html" title="class in org.apache.hadoop.hbase.client">Mutation</a>&nbsp;mutation,
                        <a href="../../../../../org/apache/hadoop/hbase/regionserver/HStore.html" title="class in org.apache.hadoop.hbase.regionserver">HStore</a>&nbsp;store,
                        <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;coordinates,
                        <a href="../../../../../org/apache/hadoop/hbase/client/IsolationLevel.html" title="enum in org.apache.hadoop.hbase.client">IsolationLevel</a>&nbsp;isolation,
@@ -7584,7 +7584,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>sort</h4>
-<pre>private static&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8210">sort</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;cells,
+<pre>private static&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8213">sort</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&nbsp;cells,
                                <a href="../../../../../org/apache/hadoop/hbase/CellComparator.html" title="interface in org.apache.hadoop.hbase">CellComparator</a>&nbsp;comparator)</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
@@ -7598,7 +7598,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>heapSize</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8249">heapSize</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8252">heapSize</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/io/HeapSize.html#heapSize--">heapSize</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/io/HeapSize.html" title="interface in org.apache.hadoop.hbase.io">HeapSize</a></code></dd>
@@ -7614,7 +7614,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>registerService</h4>
-<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8269">registerService</a>(com.google.protobuf.Service&nbsp;instance)</pre>
+<pre>public&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8272">registerService</a>(com.google.protobuf.Service&nbsp;instance)</pre>
 <div class="block">Registers a new protocol buffer <code>Service</code> subclass as a coprocessor endpoint to
  be available for handling Region#execService(com.google.protobuf.RpcController,
     org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.
@@ -7640,7 +7640,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>execService</h4>
-<pre>public&nbsp;com.google.protobuf.Message&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8304">execService</a>(com.google.protobuf.RpcController&nbsp;controller,
+<pre>public&nbsp;com.google.protobuf.Message&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8307">execService</a>(com.google.protobuf.RpcController&nbsp;controller,
                                                org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceCall&nbsp;call)
                                         throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Executes a single protocol buffer coprocessor endpoint <code>Service</code> method using
@@ -7668,7 +7668,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>shouldForceSplit</h4>
-<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8355">shouldForceSplit</a>()</pre>
+<pre>boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8358">shouldForceSplit</a>()</pre>
 </li>
 </ul>
 <a name="getExplicitSplitPoint--">
@@ -7677,7 +7677,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getExplicitSplitPoint</h4>
-<pre>byte[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8359">getExplicitSplitPoint</a>()</pre>
+<pre>byte[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8362">getExplicitSplitPoint</a>()</pre>
 </li>
 </ul>
 <a name="forceSplit-byte:A-">
@@ -7686,7 +7686,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>forceSplit</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8363">forceSplit</a>(byte[]&nbsp;sp)</pre>
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8366">forceSplit</a>(byte[]&nbsp;sp)</pre>
 </li>
 </ul>
 <a name="clearSplit--">
@@ -7695,7 +7695,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>clearSplit</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8372">clearSplit</a>()</pre>
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8375">clearSplit</a>()</pre>
 </li>
 </ul>
 <a name="checkSplit--">
@@ -7704,7 +7704,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>checkSplit</h4>
-<pre>public&nbsp;byte[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8383">checkSplit</a>()</pre>
+<pre>public&nbsp;byte[]&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8386">checkSplit</a>()</pre>
 <div class="block">Return the splitpoint. null indicates the region isn't splittable
  If the splitpoint isn't explicitly specified, it will go over the stores
  to find the best splitpoint. Currently the criteria of best splitpoint
@@ -7717,7 +7717,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getCompactPriority</h4>
-<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8417">getCompactPriority</a>()</pre>
+<pre>public&nbsp;int&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8420">getCompactPriority</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>The priority that this region should have in the compaction queue</dd>
@@ -7730,7 +7730,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getCoprocessorHost</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.html" title="class in org.apache.hadoop.hbase.regionserver">RegionCoprocessorHost</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8423">getCoprocessorHost</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.html" title="class in org.apache.hadoop.hbase.regionserver">RegionCoprocessorHost</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8426">getCoprocessorHost</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>the coprocessor host</dd>
@@ -7743,7 +7743,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setCoprocessorHost</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8429">setCoprocessorHost</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.html" title="class in org.apache.hadoop.hbase.regionserver">RegionCoprocessorHost</a>&nbsp;coprocessorHost)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8432">setCoprocessorHost</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.html" title="class in org.apache.hadoop.hbase.regionserver">RegionCoprocessorHost</a>&nbsp;coprocessorHost)</pre>
 <dl>
 <dt><span class="paramLabel">Parameters:</span></dt>
 <dd><code>coprocessorHost</code> - the new coprocessor host</dd>
@@ -7756,7 +7756,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>startRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8434">startRegionOperation</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8437">startRegionOperation</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#startRegionOperation--">Region</a></code></span></div>
 <div class="block">This method needs to be called before any public call that reads or
@@ -7778,7 +7778,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>startRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8439">startRegionOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8442">startRegionOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;op)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#startRegionOperation-org.apache.hadoop.hbase.regionserver.Region.Operation-">Region</a></code></span></div>
 <div class="block">This method needs to be called before any public call that reads or
@@ -7802,7 +7802,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>closeRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8478">closeRegionOperation</a>()
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8481">closeRegionOperation</a>()
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#closeRegionOperation--">Region</a></code></span></div>
 <div class="block">Closes the region operation lock.</div>
@@ -7820,7 +7820,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>closeRegionOperation</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8483">closeRegionOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;operation)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8486">closeRegionOperation</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.Operation.html" title="enum in org.apache.hadoop.hbase.regionserver">Region.Operation</a>&nbsp;operation)
                           throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#closeRegionOperation-org.apache.hadoop.hbase.regionserver.Region.Operation-">Region</a></code></span></div>
 <div class="block">Closes the region operation lock. This needs to be called in the finally block corresponding
@@ -7839,7 +7839,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>startBulkRegionOperation</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8502">startBulkRegionOperation</a>(boolean&nbsp;writeLockNeeded)
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8505">startBulkRegionOperation</a>(boolean&nbsp;writeLockNeeded)
                                throws <a href="../../../../../org/apache/hadoop/hbase/NotServingRegionException.html" title="class in org.apache.hadoop.hbase">NotServingRegionException</a>,
                                       <a href="../../../../../org/apache/hadoop/hbase/RegionTooBusyException.html" title="class in org.apache.hadoop.hbase">RegionTooBusyException</a>,
                                       <a href="https://docs.oracle.com/javase/8/docs/api/java/io/InterruptedIOException.html?is-external=true" title="class or interface in java.io">InterruptedIOException</a></pre>
@@ -7861,7 +7861,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>closeBulkRegionOperation</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8520">closeBulkRegionOperation</a>()</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8523">closeBulkRegionOperation</a>()</pre>
 <div class="block">Closes the lock. This needs to be called in the finally block corresponding
  to the try block of #startRegionOperation</div>
 </li>
@@ -7872,7 +7872,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>recordMutationWithoutWal</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8529">recordMutationWithoutWal</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap)</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8532">recordMutationWithoutWal</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../../../org/apache/hadoop/hbase/Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a>&gt;&gt;&nbsp;familyMap)</pre>
 <div class="block">Update LongAdders for number of puts without wal and the size of possible data loss.
  These information are exposed by the region server metrics.</div>
 </li>
@@ -7883,7 +7883,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>lock</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8551">lock</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;lock)
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8554">lock</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;lock)
            throws <a href="../../../../../org/apache/hadoop/hbase/RegionTooBusyException.html" title="class in org.apache.hadoop.hbase">RegionTooBusyException</a>,
                   <a href="https://docs.oracle.com/javase/8/docs/api/java/io/InterruptedIOException.html?is-external=true" title="class or interface in java.io">InterruptedIOException</a></pre>
 <dl>
@@ -7899,7 +7899,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>lock</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8560">lock</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;lock,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8563">lock</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html?is-external=true" title="class or interface in java.util.concurrent.locks">Lock</a>&nbsp;lock,
                   int&nbsp;multiplier)
            throws <a href="../../../../../org/apache/hadoop/hbase/RegionTooBusyException.html" title="class in org.apache.hadoop.hbase">RegionTooBusyException</a>,
                   <a href="https://docs.oracle.com/javase/8/docs/api/java/io/InterruptedIOException.html?is-external=true" title="class or interface in java.io">InterruptedIOException</a></pre>
@@ -7919,7 +7919,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>sync</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8587">sync</a>(long&nbsp;txid,
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8590">sync</a>(long&nbsp;txid,
                   <a href="../../../../../org/apache/hadoop/hbase/client/Durability.html" title="enum in org.apache.hadoop.hbase.client">Durability</a>&nbsp;durability)
            throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block">Calls sync with the given transaction ID</div>
@@ -7937,7 +7937,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>shouldSyncWAL</h4>
-<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8619">shouldSyncWAL</a>()</pre>
+<pre>private&nbsp;boolean&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8622">shouldSyncWAL</a>()</pre>
 <div class="block">Check whether we should sync the wal from the table's durability settings</div>
 </li>
 </ul>
@@ -7947,7 +7947,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOpenSeqNum</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8650">getOpenSeqNum</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8653">getOpenSeqNum</a>()</pre>
 <dl>
 <dt><span class="returnLabel">Returns:</span></dt>
 <dd>the latest sequence number that was read from storage when this region was opened</dd>
@@ -7960,7 +7960,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMaxStoreSeqId</h4>
-<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html?is-external=true" title="class or interface in java.lang">Long</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8655">getMaxStoreSeqId</a>()</pre>
+<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Map.html?is-external=true" title="class or interface in java.util">Map</a>&lt;byte[],<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html?is-external=true" title="class or interface in java.lang">Long</a>&gt;&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8658">getMaxStoreSeqId</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getMaxStoreSeqId--">getMaxStoreSeqId</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a></code></dd>
@@ -7976,7 +7976,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOldestSeqIdOfStore</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8659">getOldestSeqIdOfStore</a>(byte[]&nbsp;familyName)</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8662">getOldestSeqIdOfStore</a>(byte[]&nbsp;familyName)</pre>
 </li>
 </ul>
 <a name="getCompactionState--">
@@ -7985,7 +7985,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getCompactionState</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/CompactionState.html" title="enum in org.apache.hadoop.hbase.client">CompactionState</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8664">getCompactionState</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/client/CompactionState.html" title="enum in org.apache.hadoop.hbase.client">CompactionState</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8667">getCompactionState</a>()</pre>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getCompactionState--">getCompactionState</a></code>&nbsp;in interface&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html" title="interface in org.apache.hadoop.hbase.regionserver">Region</a></code></dd>
@@ -8000,7 +8000,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>reportCompactionRequestStart</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8670">reportCompactionRequestStart</a>(boolean&nbsp;isMajor)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8673">reportCompactionRequestStart</a>(boolean&nbsp;isMajor)</pre>
 </li>
 </ul>
 <a name="reportCompactionRequestEnd-boolean-int-long-">
@@ -8009,7 +8009,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>reportCompactionRequestEnd</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8674">reportCompactionRequestEnd</a>(boolean&nbsp;isMajor,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8677">reportCompactionRequestEnd</a>(boolean&nbsp;isMajor,
                                        int&nbsp;numFiles,
                                        long&nbsp;filesSizeCompacted)</pre>
 </li>
@@ -8020,7 +8020,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>reportCompactionRequestFailure</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8685">reportCompactionRequestFailure</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8688">reportCompactionRequestFailure</a>()</pre>
 </li>
 </ul>
 <a name="incrementCompactionsQueuedCount--">
@@ -8029,7 +8029,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>incrementCompactionsQueuedCount</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8689">incrementCompactionsQueuedCount</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8692">incrementCompactionsQueuedCount</a>()</pre>
 </li>
 </ul>
 <a name="decrementCompactionsQueuedCount--">
@@ -8038,7 +8038,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>decrementCompactionsQueuedCount</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8693">decrementCompactionsQueuedCount</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8696">decrementCompactionsQueuedCount</a>()</pre>
 </li>
 </ul>
 <a name="incrementFlushesQueuedCount--">
@@ -8047,7 +8047,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>incrementFlushesQueuedCount</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8697">incrementFlushesQueuedCount</a>()</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8700">incrementFlushesQueuedCount</a>()</pre>
 </li>
 </ul>
 <a name="getReadPoint--">
@@ -8056,7 +8056,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getReadPoint</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8702">getReadPoint</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8705">getReadPoint</a>()</pre>
 </li>
 </ul>
 <a name="onConfigurationChange-org.apache.hadoop.conf.Configuration-">
@@ -8065,7 +8065,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>onConfigurationChange</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8710">onConfigurationChange</a>(org.apache.hadoop.conf.Configuration&nbsp;conf)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8713">onConfigurationChange</a>(org.apache.hadoop.conf.Configuration&nbsp;conf)</pre>
 <div class="block">This method would be called by the <a href="../../../../../org/apache/hadoop/hbase/conf/ConfigurationManager.html" title="class in org.apache.hadoop.hbase.conf"><code>ConfigurationManager</code></a>
  object when the <code>Configuration</code> object is reloaded from disk.</div>
 <dl>
@@ -8080,7 +8080,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>registerChildren</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8718">registerChildren</a>(<a href="../../../../../org/apache/hadoop/hbase/conf/ConfigurationManager.html" title="class in org.apache.hadoop.hbase.conf">ConfigurationManager</a>&nbsp;manager)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8721">registerChildren</a>(<a href="../../../../../org/apache/hadoop/hbase/conf/ConfigurationManager.html" title="class in org.apache.hadoop.hbase.conf">ConfigurationManager</a>&nbsp;manager)</pre>
 <div class="block">Needs to be called to register the children to the manager.</div>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -8096,7 +8096,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>deregisterChildren</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8727">deregisterChildren</a>(<a href="../../../../../org/apache/hadoop/hbase/conf/ConfigurationManager.html" title="class in org.apache.hadoop.hbase.conf">ConfigurationManager</a>&nbsp;manager)</pre>
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8730">deregisterChildren</a>(<a href="../../../../../org/apache/hadoop/hbase/conf/ConfigurationManager.html" title="class in org.apache.hadoop.hbase.conf">ConfigurationManager</a>&nbsp;manager)</pre>
 <div class="block">Needs to be called to deregister the children from the manager.</div>
 <dl>
 <dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
@@ -8112,7 +8112,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getCellComparator</h4>
-<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/CellComparator.html" title="interface in org.apache.hadoop.hbase">CellComparator</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8732">getCellComparator</a>()</pre>
+<pre>public&nbsp;<a href="../../../../../org/apache/hadoop/hbase/CellComparator.html" title="interface in org.apache.hadoop.hbase">CellComparator</a>&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8735">getCellComparator</a>()</pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#getCellComparator--">Region</a></code></span></div>
 <div class="block">The comparator to be used with the region</div>
 <dl>
@@ -8127,7 +8127,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMemStoreFlushSize</h4>
-<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8737">getMemStoreFlushSize</a>()</pre>
+<pre>public&nbsp;long&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8740">getMemStoreFlushSize</a>()</pre>
 </li>
 </ul>
 <a name="throwException-java.lang.String-java.lang.String-">
@@ -8136,7 +8136,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>throwException</h4>
-<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8743">throwException</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;title,
+<pre>void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8746">throwException</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;title,
                     <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;regionName)</pre>
 </li>
 </ul>
@@ -8146,7 +8146,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>requestCompaction</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8764">requestCompaction</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;why,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8767">requestCompaction</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;why,
                               int&nbsp;priority,
                               boolean&nbsp;major,
                               <a href="../../../../../org/apache/hadoop/hbase/regionserver/compactions/CompactionLifeCycleTracker.html" title="interface in org.apache.hadoop.hbase.regionserver.compactions">CompactionLifeCycleTracker</a>&nbsp;tracker)
@@ -8167,7 +8167,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>requestCompaction</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8774">requestCompaction</a>(byte[]&nbsp;family,
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8777">requestCompaction</a>(byte[]&nbsp;family,
                               <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;why,
                               int&nbsp;priority,
                               boolean&nbsp;major,
@@ -8189,7 +8189,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>requestFlushIfNeeded</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8788">requestFlushIfNeeded</a>()
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8791">requestFlushIfNeeded</a>()
                            throws <a href="../../../../../org/apache/hadoop/hbase/RegionTooBusyException.html" title="class in org.apache.hadoop.hbase">RegionTooBusyException</a></pre>
 <dl>
 <dt><span class="throwsLabel">Throws:</span></dt>
@@ -8203,7 +8203,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>requestFlush</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8794">requestFlush</a>()</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8797">requestFlush</a>()</pre>
 </li>
 </ul>
 <a name="requestFlush0-org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker-">
@@ -8212,7 +8212,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>requestFlush0</h4>
-<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8801">requestFlush0</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/FlushLifeCycleTracker.html" title="interface in org.apache.hadoop.hbase.regionserver">FlushLifeCycleTracker</a>&nbsp;tracker)</pre>
+<pre>private&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8804">requestFlush0</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/FlushLifeCycleTracker.html" title="interface in org.apache.hadoop.hbase.regionserver">FlushLifeCycleTracker</a>&nbsp;tracker)</pre>
 </li>
 </ul>
 <a name="requestFlush-org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker-">
@@ -8221,7 +8221,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>requestFlush</h4>
-<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8821">requestFlush</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/FlushLifeCycleTracker.html" title="interface in org.apache.hadoop.hbase.regionserver">FlushLifeCycleTracker</a>&nbsp;tracker)
+<pre>public&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8824">requestFlush</a>(<a href="../../../../../org/apache/hadoop/hbase/regionserver/FlushLifeCycleTracker.html" title="interface in org.apache.hadoop.hbase.regionserver">FlushLifeCycleTracker</a>&nbsp;tracker)
                   throws <a href="https://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true" title="class or interface in java.io">IOException</a></pre>
 <div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../../../../org/apache/hadoop/hbase/regionserver/Region.html#requestFlush-org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker-">Region</a></code></span></div>
 <div class="block">Request flush on this region.</div>
@@ -8239,7 +8239,7 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>decorateRegionConfiguration</h4>
-<pre>static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8830">decorateRegionConfiguration</a>(org.apache.hadoop.conf.Configuration&nbsp;conf)</pre>
+<pre>static&nbsp;void&nbsp;<a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/HRegion.html#line.8833">decorateRegionConfiguration</a>(org.apache.hadoop.conf.Configuration&nbsp;conf)</pre>
 <div class="block">This method modifies the region's configuration in order to inject replication-related
  features</div>
 <dl>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CloseableVisitor.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CloseableVisitor.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CloseableVisitor.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CloseableVisitor.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectAllVisitor.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectAllVisitor.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectAllVisitor.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectAllVisitor.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectingVisitor.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectingVisitor.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectingVisitor.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.CollectingVisitor.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.DefaultVisitorBase.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.DefaultVisitorBase.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.DefaultVisitorBase.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.DefaultVisitorBase.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.QueryType.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.QueryType.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.QueryType.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.QueryType.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.ReplicationBarrierResult.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.ReplicationBarrierResult.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.ReplicationBarrierResult.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.ReplicationBarrierResult.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.Visitor.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.Visitor.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.Visitor.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.Visitor.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.html b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.html
index ff06e00..cf8f46d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/MetaTableAccessor.html
@@ -1663,7 +1663,7 @@
 <span class="sourceLineNo">1655</span>   * Construct PUT for given state<a name="line.1655"></a>
 <span class="sourceLineNo">1656</span>   * @param state new state<a name="line.1656"></a>
 <span class="sourceLineNo">1657</span>   */<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>  private static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
+<span class="sourceLineNo">1658</span>  public static Put makePutFromTableState(TableState state, long ts) {<a name="line.1658"></a>
 <span class="sourceLineNo">1659</span>    Put put = new Put(state.getTableName().getName(), ts);<a name="line.1659"></a>
 <span class="sourceLineNo">1660</span>    put.addColumn(getTableFamily(), getTableStateColumn(), state.convert().toByteArray());<a name="line.1660"></a>
 <span class="sourceLineNo">1661</span>    return put;<a name="line.1661"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/Version.html b/devapidocs/src-html/org/apache/hadoop/hbase/Version.html
index 3cd077d..9e88733 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/Version.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/Version.html
@@ -16,9 +16,9 @@
 <span class="sourceLineNo">008</span>@InterfaceAudience.Private<a name="line.8"></a>
 <span class="sourceLineNo">009</span>public class Version {<a name="line.9"></a>
 <span class="sourceLineNo">010</span>  public static final String version = "3.0.0-SNAPSHOT";<a name="line.10"></a>
-<span class="sourceLineNo">011</span>  public static final String revision = "8c1edb3bba56677b0ee106f340d12b42e999cdaa";<a name="line.11"></a>
+<span class="sourceLineNo">011</span>  public static final String revision = "27ed2ac071f0867df315a7e5d8acf49aabcd9399";<a name="line.11"></a>
 <span class="sourceLineNo">012</span>  public static final String user = "jenkins";<a name="line.12"></a>
-<span class="sourceLineNo">013</span>  public static final String date = "Tue Aug 13 14:35:01 UTC 2019";<a name="line.13"></a>
+<span class="sourceLineNo">013</span>  public static final String date = "Wed Aug 14 14:35:17 UTC 2019";<a name="line.13"></a>
 <span class="sourceLineNo">014</span>  public static final String url = "git://jenkins-websites-he-de.apache.org/home/jenkins/jenkins-slave/workspace/hbase_generate_website/hbase";<a name="line.14"></a>
 <span class="sourceLineNo">015</span>  public static final String srcChecksum = "(stdin)=";<a name="line.15"></a>
 <span class="sourceLineNo">016</span>}<a name="line.16"></a>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.Visitor.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BatchOperation.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.Result.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResult.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.FlushResultImpl.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.MutationBatchOperation.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ObservedExceptionsInBatch.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ObservedExceptionsInBatch.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ObservedExceptionsInBatch.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ObservedExceptionsInBatch.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.PrepareFlushResult.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RegionScannerImpl.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.ReplayBatchOperation.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockContext.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.RowLockImpl.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.WriteState.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.WriteState.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.WriteState.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.WriteState.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.html
index e7c31b5..a1cbc27 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.html
@@ -1553,7299 +1553,7302 @@
 <span class="sourceLineNo">1545</span>    MonitoredTask status = TaskMonitor.get().createStatus(<a name="line.1545"></a>
 <span class="sourceLineNo">1546</span>        "Closing region " + this.getRegionInfo().getEncodedName() +<a name="line.1546"></a>
 <span class="sourceLineNo">1547</span>        (abort ? " due to abort" : ""));<a name="line.1547"></a>
-<span class="sourceLineNo">1548</span><a name="line.1548"></a>
+<span class="sourceLineNo">1548</span>    status.enableStatusJournal(false);<a name="line.1548"></a>
 <span class="sourceLineNo">1549</span>    status.setStatus("Waiting for close lock");<a name="line.1549"></a>
 <span class="sourceLineNo">1550</span>    try {<a name="line.1550"></a>
 <span class="sourceLineNo">1551</span>      synchronized (closeLock) {<a name="line.1551"></a>
 <span class="sourceLineNo">1552</span>        return doClose(abort, status);<a name="line.1552"></a>
 <span class="sourceLineNo">1553</span>      }<a name="line.1553"></a>
 <span class="sourceLineNo">1554</span>    } finally {<a name="line.1554"></a>
-<span class="sourceLineNo">1555</span>      status.cleanup();<a name="line.1555"></a>
-<span class="sourceLineNo">1556</span>    }<a name="line.1556"></a>
-<span class="sourceLineNo">1557</span>  }<a name="line.1557"></a>
-<span class="sourceLineNo">1558</span><a name="line.1558"></a>
-<span class="sourceLineNo">1559</span>  /**<a name="line.1559"></a>
-<span class="sourceLineNo">1560</span>   * Exposed for some very specific unit tests.<a name="line.1560"></a>
-<span class="sourceLineNo">1561</span>   */<a name="line.1561"></a>
-<span class="sourceLineNo">1562</span>  @VisibleForTesting<a name="line.1562"></a>
-<span class="sourceLineNo">1563</span>  public void setClosing(boolean closing) {<a name="line.1563"></a>
-<span class="sourceLineNo">1564</span>    this.closing.set(closing);<a name="line.1564"></a>
-<span class="sourceLineNo">1565</span>  }<a name="line.1565"></a>
-<span class="sourceLineNo">1566</span><a name="line.1566"></a>
-<span class="sourceLineNo">1567</span>  /**<a name="line.1567"></a>
-<span class="sourceLineNo">1568</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1568"></a>
-<span class="sourceLineNo">1569</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1569"></a>
-<span class="sourceLineNo">1570</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1570"></a>
-<span class="sourceLineNo">1571</span>   */<a name="line.1571"></a>
-<span class="sourceLineNo">1572</span>  @VisibleForTesting<a name="line.1572"></a>
-<span class="sourceLineNo">1573</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1573"></a>
-<span class="sourceLineNo">1574</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1574"></a>
-<span class="sourceLineNo">1575</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1575"></a>
-<span class="sourceLineNo">1576</span>  }<a name="line.1576"></a>
-<span class="sourceLineNo">1577</span><a name="line.1577"></a>
-<span class="sourceLineNo">1578</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1578"></a>
-<span class="sourceLineNo">1579</span>      justification="I think FindBugs is confused")<a name="line.1579"></a>
-<span class="sourceLineNo">1580</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1580"></a>
-<span class="sourceLineNo">1581</span>      throws IOException {<a name="line.1581"></a>
-<span class="sourceLineNo">1582</span>    if (isClosed()) {<a name="line.1582"></a>
-<span class="sourceLineNo">1583</span>      LOG.warn("Region " + this + " already closed");<a name="line.1583"></a>
-<span class="sourceLineNo">1584</span>      return null;<a name="line.1584"></a>
-<span class="sourceLineNo">1585</span>    }<a name="line.1585"></a>
-<span class="sourceLineNo">1586</span><a name="line.1586"></a>
-<span class="sourceLineNo">1587</span>    if (coprocessorHost != null) {<a name="line.1587"></a>
-<span class="sourceLineNo">1588</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1588"></a>
-<span class="sourceLineNo">1589</span>      this.coprocessorHost.preClose(abort);<a name="line.1589"></a>
-<span class="sourceLineNo">1590</span>    }<a name="line.1590"></a>
-<span class="sourceLineNo">1591</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1591"></a>
-<span class="sourceLineNo">1592</span>    boolean canFlush = true;<a name="line.1592"></a>
-<span class="sourceLineNo">1593</span>    synchronized (writestate) {<a name="line.1593"></a>
-<span class="sourceLineNo">1594</span>      // Disable compacting and flushing by background threads for this<a name="line.1594"></a>
-<span class="sourceLineNo">1595</span>      // region.<a name="line.1595"></a>
-<span class="sourceLineNo">1596</span>      canFlush = !writestate.readOnly;<a name="line.1596"></a>
-<span class="sourceLineNo">1597</span>      writestate.writesEnabled = false;<a name="line.1597"></a>
-<span class="sourceLineNo">1598</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1598"></a>
-<span class="sourceLineNo">1599</span>          this.getRegionInfo().getEncodedName());<a name="line.1599"></a>
-<span class="sourceLineNo">1600</span>      waitForFlushesAndCompactions();<a name="line.1600"></a>
-<span class="sourceLineNo">1601</span>    }<a name="line.1601"></a>
-<span class="sourceLineNo">1602</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1602"></a>
-<span class="sourceLineNo">1603</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1603"></a>
-<span class="sourceLineNo">1604</span>    // the close flag?<a name="line.1604"></a>
-<span class="sourceLineNo">1605</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1605"></a>
-<span class="sourceLineNo">1606</span>      status.setStatus("Pre-flushing region before close");<a name="line.1606"></a>
-<span class="sourceLineNo">1607</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1607"></a>
-<span class="sourceLineNo">1608</span>      try {<a name="line.1608"></a>
-<span class="sourceLineNo">1609</span>        internalFlushcache(status);<a name="line.1609"></a>
-<span class="sourceLineNo">1610</span>      } catch (IOException ioe) {<a name="line.1610"></a>
-<span class="sourceLineNo">1611</span>        // Failed to flush the region. Keep going.<a name="line.1611"></a>
-<span class="sourceLineNo">1612</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1612"></a>
-<span class="sourceLineNo">1613</span>      }<a name="line.1613"></a>
-<span class="sourceLineNo">1614</span>    }<a name="line.1614"></a>
-<span class="sourceLineNo">1615</span><a name="line.1615"></a>
-<span class="sourceLineNo">1616</span>    if (timeoutForWriteLock == null<a name="line.1616"></a>
-<span class="sourceLineNo">1617</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1617"></a>
-<span class="sourceLineNo">1618</span>      // block waiting for the lock for closing<a name="line.1618"></a>
-<span class="sourceLineNo">1619</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1619"></a>
-<span class="sourceLineNo">1620</span>    } else {<a name="line.1620"></a>
-<span class="sourceLineNo">1621</span>      try {<a name="line.1621"></a>
-<span class="sourceLineNo">1622</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1622"></a>
-<span class="sourceLineNo">1623</span>        if (!succeed) {<a name="line.1623"></a>
-<span class="sourceLineNo">1624</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1624"></a>
-<span class="sourceLineNo">1625</span>        }<a name="line.1625"></a>
-<span class="sourceLineNo">1626</span>      } catch (InterruptedException e) {<a name="line.1626"></a>
-<span class="sourceLineNo">1627</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1627"></a>
-<span class="sourceLineNo">1628</span>      }<a name="line.1628"></a>
-<span class="sourceLineNo">1629</span>    }<a name="line.1629"></a>
-<span class="sourceLineNo">1630</span>    this.closing.set(true);<a name="line.1630"></a>
-<span class="sourceLineNo">1631</span>    status.setStatus("Disabling writes for close");<a name="line.1631"></a>
-<span class="sourceLineNo">1632</span>    try {<a name="line.1632"></a>
-<span class="sourceLineNo">1633</span>      if (this.isClosed()) {<a name="line.1633"></a>
-<span class="sourceLineNo">1634</span>        status.abort("Already got closed by another process");<a name="line.1634"></a>
-<span class="sourceLineNo">1635</span>        // SplitTransaction handles the null<a name="line.1635"></a>
-<span class="sourceLineNo">1636</span>        return null;<a name="line.1636"></a>
-<span class="sourceLineNo">1637</span>      }<a name="line.1637"></a>
-<span class="sourceLineNo">1638</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1638"></a>
-<span class="sourceLineNo">1639</span>      // Don't flush the cache if we are aborting<a name="line.1639"></a>
-<span class="sourceLineNo">1640</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1640"></a>
-<span class="sourceLineNo">1641</span>        int failedfFlushCount = 0;<a name="line.1641"></a>
-<span class="sourceLineNo">1642</span>        int flushCount = 0;<a name="line.1642"></a>
-<span class="sourceLineNo">1643</span>        long tmp = 0;<a name="line.1643"></a>
-<span class="sourceLineNo">1644</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1644"></a>
-<span class="sourceLineNo">1645</span>        while (remainingSize &gt; 0) {<a name="line.1645"></a>
-<span class="sourceLineNo">1646</span>          try {<a name="line.1646"></a>
-<span class="sourceLineNo">1647</span>            internalFlushcache(status);<a name="line.1647"></a>
-<span class="sourceLineNo">1648</span>            if(flushCount &gt;0) {<a name="line.1648"></a>
-<span class="sourceLineNo">1649</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1649"></a>
-<span class="sourceLineNo">1650</span>                  " (carrying snapshot?) " + this);<a name="line.1650"></a>
-<span class="sourceLineNo">1651</span>            }<a name="line.1651"></a>
-<span class="sourceLineNo">1652</span>            flushCount++;<a name="line.1652"></a>
-<span class="sourceLineNo">1653</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1653"></a>
-<span class="sourceLineNo">1654</span>            if (tmp &gt;= remainingSize) {<a name="line.1654"></a>
-<span class="sourceLineNo">1655</span>              failedfFlushCount++;<a name="line.1655"></a>
-<span class="sourceLineNo">1656</span>            }<a name="line.1656"></a>
-<span class="sourceLineNo">1657</span>            remainingSize = tmp;<a name="line.1657"></a>
-<span class="sourceLineNo">1658</span>            if (failedfFlushCount &gt; 5) {<a name="line.1658"></a>
-<span class="sourceLineNo">1659</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1659"></a>
-<span class="sourceLineNo">1660</span>              // so we do not lose data<a name="line.1660"></a>
-<span class="sourceLineNo">1661</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1661"></a>
-<span class="sourceLineNo">1662</span>                  flushCount + " attempts on region: " +<a name="line.1662"></a>
-<span class="sourceLineNo">1663</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1663"></a>
-<span class="sourceLineNo">1664</span>            }<a name="line.1664"></a>
-<span class="sourceLineNo">1665</span>          } catch (IOException ioe) {<a name="line.1665"></a>
-<span class="sourceLineNo">1666</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1666"></a>
-<span class="sourceLineNo">1667</span>            synchronized (writestate) {<a name="line.1667"></a>
-<span class="sourceLineNo">1668</span>              writestate.writesEnabled = true;<a name="line.1668"></a>
-<span class="sourceLineNo">1669</span>            }<a name="line.1669"></a>
-<span class="sourceLineNo">1670</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1670"></a>
-<span class="sourceLineNo">1671</span>            throw ioe;<a name="line.1671"></a>
-<span class="sourceLineNo">1672</span>          }<a name="line.1672"></a>
-<span class="sourceLineNo">1673</span>        }<a name="line.1673"></a>
-<span class="sourceLineNo">1674</span>      }<a name="line.1674"></a>
-<span class="sourceLineNo">1675</span><a name="line.1675"></a>
-<span class="sourceLineNo">1676</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1676"></a>
-<span class="sourceLineNo">1677</span>      if (!stores.isEmpty()) {<a name="line.1677"></a>
-<span class="sourceLineNo">1678</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1678"></a>
-<span class="sourceLineNo">1679</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1679"></a>
-<span class="sourceLineNo">1680</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1680"></a>
-<span class="sourceLineNo">1681</span>            getRegionInfo().getRegionNameAsString());<a name="line.1681"></a>
-<span class="sourceLineNo">1682</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1682"></a>
-<span class="sourceLineNo">1683</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1683"></a>
-<span class="sourceLineNo">1684</span><a name="line.1684"></a>
-<span class="sourceLineNo">1685</span>        // close each store in parallel<a name="line.1685"></a>
-<span class="sourceLineNo">1686</span>        for (HStore store : stores.values()) {<a name="line.1686"></a>
-<span class="sourceLineNo">1687</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1687"></a>
-<span class="sourceLineNo">1688</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1688"></a>
-<span class="sourceLineNo">1689</span>            if (getRegionServerServices() != null) {<a name="line.1689"></a>
-<span class="sourceLineNo">1690</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1690"></a>
-<span class="sourceLineNo">1691</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1691"></a>
-<span class="sourceLineNo">1692</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1692"></a>
-<span class="sourceLineNo">1693</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1693"></a>
-<span class="sourceLineNo">1694</span>                  ". Maybe a coprocessor "<a name="line.1694"></a>
-<span class="sourceLineNo">1695</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1695"></a>
-<span class="sourceLineNo">1696</span>            }<a name="line.1696"></a>
-<span class="sourceLineNo">1697</span>          }<a name="line.1697"></a>
-<span class="sourceLineNo">1698</span>          completionService<a name="line.1698"></a>
-<span class="sourceLineNo">1699</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1699"></a>
-<span class="sourceLineNo">1700</span>                @Override<a name="line.1700"></a>
-<span class="sourceLineNo">1701</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1701"></a>
-<span class="sourceLineNo">1702</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1702"></a>
-<span class="sourceLineNo">1703</span>                }<a name="line.1703"></a>
-<span class="sourceLineNo">1704</span>              });<a name="line.1704"></a>
-<span class="sourceLineNo">1705</span>        }<a name="line.1705"></a>
-<span class="sourceLineNo">1706</span>        try {<a name="line.1706"></a>
-<span class="sourceLineNo">1707</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1707"></a>
-<span class="sourceLineNo">1708</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1708"></a>
-<span class="sourceLineNo">1709</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1709"></a>
-<span class="sourceLineNo">1710</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1710"></a>
-<span class="sourceLineNo">1711</span>            if (familyFiles == null) {<a name="line.1711"></a>
-<span class="sourceLineNo">1712</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1712"></a>
-<span class="sourceLineNo">1713</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1713"></a>
-<span class="sourceLineNo">1714</span>            }<a name="line.1714"></a>
-<span class="sourceLineNo">1715</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1715"></a>
-<span class="sourceLineNo">1716</span>          }<a name="line.1716"></a>
-<span class="sourceLineNo">1717</span>        } catch (InterruptedException e) {<a name="line.1717"></a>
-<span class="sourceLineNo">1718</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1718"></a>
-<span class="sourceLineNo">1719</span>        } catch (ExecutionException e) {<a name="line.1719"></a>
-<span class="sourceLineNo">1720</span>          Throwable cause = e.getCause();<a name="line.1720"></a>
-<span class="sourceLineNo">1721</span>          if (cause instanceof IOException) {<a name="line.1721"></a>
-<span class="sourceLineNo">1722</span>            throw (IOException) cause;<a name="line.1722"></a>
-<span class="sourceLineNo">1723</span>          }<a name="line.1723"></a>
-<span class="sourceLineNo">1724</span>          throw new IOException(cause);<a name="line.1724"></a>
-<span class="sourceLineNo">1725</span>        } finally {<a name="line.1725"></a>
-<span class="sourceLineNo">1726</span>          storeCloserThreadPool.shutdownNow();<a name="line.1726"></a>
-<span class="sourceLineNo">1727</span>        }<a name="line.1727"></a>
-<span class="sourceLineNo">1728</span>      }<a name="line.1728"></a>
-<span class="sourceLineNo">1729</span><a name="line.1729"></a>
-<span class="sourceLineNo">1730</span>      status.setStatus("Writing region close event to WAL");<a name="line.1730"></a>
-<span class="sourceLineNo">1731</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1731"></a>
-<span class="sourceLineNo">1732</span>      // do not write any data into the region.<a name="line.1732"></a>
-<span class="sourceLineNo">1733</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1733"></a>
-<span class="sourceLineNo">1734</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1734"></a>
-<span class="sourceLineNo">1735</span>        writeRegionCloseMarker(wal);<a name="line.1735"></a>
-<span class="sourceLineNo">1736</span>      }<a name="line.1736"></a>
-<span class="sourceLineNo">1737</span><a name="line.1737"></a>
-<span class="sourceLineNo">1738</span>      this.closed.set(true);<a name="line.1738"></a>
-<span class="sourceLineNo">1739</span>      if (!canFlush) {<a name="line.1739"></a>
-<span class="sourceLineNo">1740</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1740"></a>
-<span class="sourceLineNo">1741</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1741"></a>
-<span class="sourceLineNo">1742</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1742"></a>
-<span class="sourceLineNo">1743</span>      }<a name="line.1743"></a>
-<span class="sourceLineNo">1744</span>      if (coprocessorHost != null) {<a name="line.1744"></a>
-<span class="sourceLineNo">1745</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1745"></a>
-<span class="sourceLineNo">1746</span>        this.coprocessorHost.postClose(abort);<a name="line.1746"></a>
-<span class="sourceLineNo">1747</span>      }<a name="line.1747"></a>
-<span class="sourceLineNo">1748</span>      if (this.metricsRegion != null) {<a name="line.1748"></a>
-<span class="sourceLineNo">1749</span>        this.metricsRegion.close();<a name="line.1749"></a>
+<span class="sourceLineNo">1555</span>      if (LOG.isDebugEnabled()) {<a name="line.1555"></a>
+<span class="sourceLineNo">1556</span>        LOG.debug("Region close journal:\n" + status.prettyPrintJournal());<a name="line.1556"></a>
+<span class="sourceLineNo">1557</span>      }<a name="line.1557"></a>
+<span class="sourceLineNo">1558</span>      status.cleanup();<a name="line.1558"></a>
+<span class="sourceLineNo">1559</span>    }<a name="line.1559"></a>
+<span class="sourceLineNo">1560</span>  }<a name="line.1560"></a>
+<span class="sourceLineNo">1561</span><a name="line.1561"></a>
+<span class="sourceLineNo">1562</span>  /**<a name="line.1562"></a>
+<span class="sourceLineNo">1563</span>   * Exposed for some very specific unit tests.<a name="line.1563"></a>
+<span class="sourceLineNo">1564</span>   */<a name="line.1564"></a>
+<span class="sourceLineNo">1565</span>  @VisibleForTesting<a name="line.1565"></a>
+<span class="sourceLineNo">1566</span>  public void setClosing(boolean closing) {<a name="line.1566"></a>
+<span class="sourceLineNo">1567</span>    this.closing.set(closing);<a name="line.1567"></a>
+<span class="sourceLineNo">1568</span>  }<a name="line.1568"></a>
+<span class="sourceLineNo">1569</span><a name="line.1569"></a>
+<span class="sourceLineNo">1570</span>  /**<a name="line.1570"></a>
+<span class="sourceLineNo">1571</span>   * The {@link HRegion#doClose} will block forever if someone tries proving the dead lock via the unit test.<a name="line.1571"></a>
+<span class="sourceLineNo">1572</span>   * Instead of blocking, the {@link HRegion#doClose} will throw exception if you set the timeout.<a name="line.1572"></a>
+<span class="sourceLineNo">1573</span>   * @param timeoutForWriteLock the second time to wait for the write lock in {@link HRegion#doClose}<a name="line.1573"></a>
+<span class="sourceLineNo">1574</span>   */<a name="line.1574"></a>
+<span class="sourceLineNo">1575</span>  @VisibleForTesting<a name="line.1575"></a>
+<span class="sourceLineNo">1576</span>  public void setTimeoutForWriteLock(long timeoutForWriteLock) {<a name="line.1576"></a>
+<span class="sourceLineNo">1577</span>    assert timeoutForWriteLock &gt;= 0;<a name="line.1577"></a>
+<span class="sourceLineNo">1578</span>    this.timeoutForWriteLock = timeoutForWriteLock;<a name="line.1578"></a>
+<span class="sourceLineNo">1579</span>  }<a name="line.1579"></a>
+<span class="sourceLineNo">1580</span><a name="line.1580"></a>
+<span class="sourceLineNo">1581</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK_EXCEPTION_PATH",<a name="line.1581"></a>
+<span class="sourceLineNo">1582</span>      justification="I think FindBugs is confused")<a name="line.1582"></a>
+<span class="sourceLineNo">1583</span>  private Map&lt;byte[], List&lt;HStoreFile&gt;&gt; doClose(boolean abort, MonitoredTask status)<a name="line.1583"></a>
+<span class="sourceLineNo">1584</span>      throws IOException {<a name="line.1584"></a>
+<span class="sourceLineNo">1585</span>    if (isClosed()) {<a name="line.1585"></a>
+<span class="sourceLineNo">1586</span>      LOG.warn("Region " + this + " already closed");<a name="line.1586"></a>
+<span class="sourceLineNo">1587</span>      return null;<a name="line.1587"></a>
+<span class="sourceLineNo">1588</span>    }<a name="line.1588"></a>
+<span class="sourceLineNo">1589</span><a name="line.1589"></a>
+<span class="sourceLineNo">1590</span>    if (coprocessorHost != null) {<a name="line.1590"></a>
+<span class="sourceLineNo">1591</span>      status.setStatus("Running coprocessor pre-close hooks");<a name="line.1591"></a>
+<span class="sourceLineNo">1592</span>      this.coprocessorHost.preClose(abort);<a name="line.1592"></a>
+<span class="sourceLineNo">1593</span>    }<a name="line.1593"></a>
+<span class="sourceLineNo">1594</span>    status.setStatus("Disabling compacts and flushes for region");<a name="line.1594"></a>
+<span class="sourceLineNo">1595</span>    boolean canFlush = true;<a name="line.1595"></a>
+<span class="sourceLineNo">1596</span>    synchronized (writestate) {<a name="line.1596"></a>
+<span class="sourceLineNo">1597</span>      // Disable compacting and flushing by background threads for this<a name="line.1597"></a>
+<span class="sourceLineNo">1598</span>      // region.<a name="line.1598"></a>
+<span class="sourceLineNo">1599</span>      canFlush = !writestate.readOnly;<a name="line.1599"></a>
+<span class="sourceLineNo">1600</span>      writestate.writesEnabled = false;<a name="line.1600"></a>
+<span class="sourceLineNo">1601</span>      LOG.debug("Closing {}, disabling compactions &amp; flushes",<a name="line.1601"></a>
+<span class="sourceLineNo">1602</span>          this.getRegionInfo().getEncodedName());<a name="line.1602"></a>
+<span class="sourceLineNo">1603</span>      waitForFlushesAndCompactions();<a name="line.1603"></a>
+<span class="sourceLineNo">1604</span>    }<a name="line.1604"></a>
+<span class="sourceLineNo">1605</span>    // If we were not just flushing, is it worth doing a preflush...one<a name="line.1605"></a>
+<span class="sourceLineNo">1606</span>    // that will clear out of the bulk of the memstore before we put up<a name="line.1606"></a>
+<span class="sourceLineNo">1607</span>    // the close flag?<a name="line.1607"></a>
+<span class="sourceLineNo">1608</span>    if (!abort &amp;&amp; worthPreFlushing() &amp;&amp; canFlush) {<a name="line.1608"></a>
+<span class="sourceLineNo">1609</span>      status.setStatus("Pre-flushing region before close");<a name="line.1609"></a>
+<span class="sourceLineNo">1610</span>      LOG.info("Running close preflush of {}", this.getRegionInfo().getEncodedName());<a name="line.1610"></a>
+<span class="sourceLineNo">1611</span>      try {<a name="line.1611"></a>
+<span class="sourceLineNo">1612</span>        internalFlushcache(status);<a name="line.1612"></a>
+<span class="sourceLineNo">1613</span>      } catch (IOException ioe) {<a name="line.1613"></a>
+<span class="sourceLineNo">1614</span>        // Failed to flush the region. Keep going.<a name="line.1614"></a>
+<span class="sourceLineNo">1615</span>        status.setStatus("Failed pre-flush " + this + "; " + ioe.getMessage());<a name="line.1615"></a>
+<span class="sourceLineNo">1616</span>      }<a name="line.1616"></a>
+<span class="sourceLineNo">1617</span>    }<a name="line.1617"></a>
+<span class="sourceLineNo">1618</span><a name="line.1618"></a>
+<span class="sourceLineNo">1619</span>    if (timeoutForWriteLock == null<a name="line.1619"></a>
+<span class="sourceLineNo">1620</span>        || timeoutForWriteLock == Long.MAX_VALUE) {<a name="line.1620"></a>
+<span class="sourceLineNo">1621</span>      // block waiting for the lock for closing<a name="line.1621"></a>
+<span class="sourceLineNo">1622</span>      lock.writeLock().lock(); // FindBugs: Complains UL_UNRELEASED_LOCK_EXCEPTION_PATH but seems fine<a name="line.1622"></a>
+<span class="sourceLineNo">1623</span>    } else {<a name="line.1623"></a>
+<span class="sourceLineNo">1624</span>      try {<a name="line.1624"></a>
+<span class="sourceLineNo">1625</span>        boolean succeed = lock.writeLock().tryLock(timeoutForWriteLock, TimeUnit.SECONDS);<a name="line.1625"></a>
+<span class="sourceLineNo">1626</span>        if (!succeed) {<a name="line.1626"></a>
+<span class="sourceLineNo">1627</span>          throw new IOException("Failed to get write lock when closing region");<a name="line.1627"></a>
+<span class="sourceLineNo">1628</span>        }<a name="line.1628"></a>
+<span class="sourceLineNo">1629</span>      } catch (InterruptedException e) {<a name="line.1629"></a>
+<span class="sourceLineNo">1630</span>        throw (InterruptedIOException) new InterruptedIOException().initCause(e);<a name="line.1630"></a>
+<span class="sourceLineNo">1631</span>      }<a name="line.1631"></a>
+<span class="sourceLineNo">1632</span>    }<a name="line.1632"></a>
+<span class="sourceLineNo">1633</span>    this.closing.set(true);<a name="line.1633"></a>
+<span class="sourceLineNo">1634</span>    status.setStatus("Disabling writes for close");<a name="line.1634"></a>
+<span class="sourceLineNo">1635</span>    try {<a name="line.1635"></a>
+<span class="sourceLineNo">1636</span>      if (this.isClosed()) {<a name="line.1636"></a>
+<span class="sourceLineNo">1637</span>        status.abort("Already got closed by another process");<a name="line.1637"></a>
+<span class="sourceLineNo">1638</span>        // SplitTransaction handles the null<a name="line.1638"></a>
+<span class="sourceLineNo">1639</span>        return null;<a name="line.1639"></a>
+<span class="sourceLineNo">1640</span>      }<a name="line.1640"></a>
+<span class="sourceLineNo">1641</span>      LOG.debug("Updates disabled for region " + this);<a name="line.1641"></a>
+<span class="sourceLineNo">1642</span>      // Don't flush the cache if we are aborting<a name="line.1642"></a>
+<span class="sourceLineNo">1643</span>      if (!abort &amp;&amp; canFlush) {<a name="line.1643"></a>
+<span class="sourceLineNo">1644</span>        int failedfFlushCount = 0;<a name="line.1644"></a>
+<span class="sourceLineNo">1645</span>        int flushCount = 0;<a name="line.1645"></a>
+<span class="sourceLineNo">1646</span>        long tmp = 0;<a name="line.1646"></a>
+<span class="sourceLineNo">1647</span>        long remainingSize = this.memStoreSizing.getDataSize();<a name="line.1647"></a>
+<span class="sourceLineNo">1648</span>        while (remainingSize &gt; 0) {<a name="line.1648"></a>
+<span class="sourceLineNo">1649</span>          try {<a name="line.1649"></a>
+<span class="sourceLineNo">1650</span>            internalFlushcache(status);<a name="line.1650"></a>
+<span class="sourceLineNo">1651</span>            if(flushCount &gt;0) {<a name="line.1651"></a>
+<span class="sourceLineNo">1652</span>              LOG.info("Running extra flush, " + flushCount +<a name="line.1652"></a>
+<span class="sourceLineNo">1653</span>                  " (carrying snapshot?) " + this);<a name="line.1653"></a>
+<span class="sourceLineNo">1654</span>            }<a name="line.1654"></a>
+<span class="sourceLineNo">1655</span>            flushCount++;<a name="line.1655"></a>
+<span class="sourceLineNo">1656</span>            tmp = this.memStoreSizing.getDataSize();<a name="line.1656"></a>
+<span class="sourceLineNo">1657</span>            if (tmp &gt;= remainingSize) {<a name="line.1657"></a>
+<span class="sourceLineNo">1658</span>              failedfFlushCount++;<a name="line.1658"></a>
+<span class="sourceLineNo">1659</span>            }<a name="line.1659"></a>
+<span class="sourceLineNo">1660</span>            remainingSize = tmp;<a name="line.1660"></a>
+<span class="sourceLineNo">1661</span>            if (failedfFlushCount &gt; 5) {<a name="line.1661"></a>
+<span class="sourceLineNo">1662</span>              // If we failed 5 times and are unable to clear memory, abort<a name="line.1662"></a>
+<span class="sourceLineNo">1663</span>              // so we do not lose data<a name="line.1663"></a>
+<span class="sourceLineNo">1664</span>              throw new DroppedSnapshotException("Failed clearing memory after " +<a name="line.1664"></a>
+<span class="sourceLineNo">1665</span>                  flushCount + " attempts on region: " +<a name="line.1665"></a>
+<span class="sourceLineNo">1666</span>                  Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.1666"></a>
+<span class="sourceLineNo">1667</span>            }<a name="line.1667"></a>
+<span class="sourceLineNo">1668</span>          } catch (IOException ioe) {<a name="line.1668"></a>
+<span class="sourceLineNo">1669</span>            status.setStatus("Failed flush " + this + ", putting online again");<a name="line.1669"></a>
+<span class="sourceLineNo">1670</span>            synchronized (writestate) {<a name="line.1670"></a>
+<span class="sourceLineNo">1671</span>              writestate.writesEnabled = true;<a name="line.1671"></a>
+<span class="sourceLineNo">1672</span>            }<a name="line.1672"></a>
+<span class="sourceLineNo">1673</span>            // Have to throw to upper layers.  I can't abort server from here.<a name="line.1673"></a>
+<span class="sourceLineNo">1674</span>            throw ioe;<a name="line.1674"></a>
+<span class="sourceLineNo">1675</span>          }<a name="line.1675"></a>
+<span class="sourceLineNo">1676</span>        }<a name="line.1676"></a>
+<span class="sourceLineNo">1677</span>      }<a name="line.1677"></a>
+<span class="sourceLineNo">1678</span><a name="line.1678"></a>
+<span class="sourceLineNo">1679</span>      Map&lt;byte[], List&lt;HStoreFile&gt;&gt; result = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.1679"></a>
+<span class="sourceLineNo">1680</span>      if (!stores.isEmpty()) {<a name="line.1680"></a>
+<span class="sourceLineNo">1681</span>        // initialize the thread pool for closing stores in parallel.<a name="line.1681"></a>
+<span class="sourceLineNo">1682</span>        ThreadPoolExecutor storeCloserThreadPool =<a name="line.1682"></a>
+<span class="sourceLineNo">1683</span>          getStoreOpenAndCloseThreadPool("StoreCloserThread-" +<a name="line.1683"></a>
+<span class="sourceLineNo">1684</span>            getRegionInfo().getRegionNameAsString());<a name="line.1684"></a>
+<span class="sourceLineNo">1685</span>        CompletionService&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; completionService =<a name="line.1685"></a>
+<span class="sourceLineNo">1686</span>          new ExecutorCompletionService&lt;&gt;(storeCloserThreadPool);<a name="line.1686"></a>
+<span class="sourceLineNo">1687</span><a name="line.1687"></a>
+<span class="sourceLineNo">1688</span>        // close each store in parallel<a name="line.1688"></a>
+<span class="sourceLineNo">1689</span>        for (HStore store : stores.values()) {<a name="line.1689"></a>
+<span class="sourceLineNo">1690</span>          MemStoreSize mss = store.getFlushableSize();<a name="line.1690"></a>
+<span class="sourceLineNo">1691</span>          if (!(abort || mss.getDataSize() == 0 || writestate.readOnly)) {<a name="line.1691"></a>
+<span class="sourceLineNo">1692</span>            if (getRegionServerServices() != null) {<a name="line.1692"></a>
+<span class="sourceLineNo">1693</span>              getRegionServerServices().abort("Assertion failed while closing store "<a name="line.1693"></a>
+<span class="sourceLineNo">1694</span>                + getRegionInfo().getRegionNameAsString() + " " + store<a name="line.1694"></a>
+<span class="sourceLineNo">1695</span>                + ". flushableSize expected=0, actual={" + mss<a name="line.1695"></a>
+<span class="sourceLineNo">1696</span>                + "}. Current memStoreSize=" + this.memStoreSizing.getMemStoreSize() +<a name="line.1696"></a>
+<span class="sourceLineNo">1697</span>                  ". Maybe a coprocessor "<a name="line.1697"></a>
+<span class="sourceLineNo">1698</span>                + "operation failed and left the memstore in a partially updated state.", null);<a name="line.1698"></a>
+<span class="sourceLineNo">1699</span>            }<a name="line.1699"></a>
+<span class="sourceLineNo">1700</span>          }<a name="line.1700"></a>
+<span class="sourceLineNo">1701</span>          completionService<a name="line.1701"></a>
+<span class="sourceLineNo">1702</span>              .submit(new Callable&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt;() {<a name="line.1702"></a>
+<span class="sourceLineNo">1703</span>                @Override<a name="line.1703"></a>
+<span class="sourceLineNo">1704</span>                public Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; call() throws IOException {<a name="line.1704"></a>
+<span class="sourceLineNo">1705</span>                  return new Pair&lt;&gt;(store.getColumnFamilyDescriptor().getName(), store.close());<a name="line.1705"></a>
+<span class="sourceLineNo">1706</span>                }<a name="line.1706"></a>
+<span class="sourceLineNo">1707</span>              });<a name="line.1707"></a>
+<span class="sourceLineNo">1708</span>        }<a name="line.1708"></a>
+<span class="sourceLineNo">1709</span>        try {<a name="line.1709"></a>
+<span class="sourceLineNo">1710</span>          for (int i = 0; i &lt; stores.size(); i++) {<a name="line.1710"></a>
+<span class="sourceLineNo">1711</span>            Future&lt;Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt;&gt; future = completionService.take();<a name="line.1711"></a>
+<span class="sourceLineNo">1712</span>            Pair&lt;byte[], Collection&lt;HStoreFile&gt;&gt; storeFiles = future.get();<a name="line.1712"></a>
+<span class="sourceLineNo">1713</span>            List&lt;HStoreFile&gt; familyFiles = result.get(storeFiles.getFirst());<a name="line.1713"></a>
+<span class="sourceLineNo">1714</span>            if (familyFiles == null) {<a name="line.1714"></a>
+<span class="sourceLineNo">1715</span>              familyFiles = new ArrayList&lt;&gt;();<a name="line.1715"></a>
+<span class="sourceLineNo">1716</span>              result.put(storeFiles.getFirst(), familyFiles);<a name="line.1716"></a>
+<span class="sourceLineNo">1717</span>            }<a name="line.1717"></a>
+<span class="sourceLineNo">1718</span>            familyFiles.addAll(storeFiles.getSecond());<a name="line.1718"></a>
+<span class="sourceLineNo">1719</span>          }<a name="line.1719"></a>
+<span class="sourceLineNo">1720</span>        } catch (InterruptedException e) {<a name="line.1720"></a>
+<span class="sourceLineNo">1721</span>          throw (InterruptedIOException)new InterruptedIOException().initCause(e);<a name="line.1721"></a>
+<span class="sourceLineNo">1722</span>        } catch (ExecutionException e) {<a name="line.1722"></a>
+<span class="sourceLineNo">1723</span>          Throwable cause = e.getCause();<a name="line.1723"></a>
+<span class="sourceLineNo">1724</span>          if (cause instanceof IOException) {<a name="line.1724"></a>
+<span class="sourceLineNo">1725</span>            throw (IOException) cause;<a name="line.1725"></a>
+<span class="sourceLineNo">1726</span>          }<a name="line.1726"></a>
+<span class="sourceLineNo">1727</span>          throw new IOException(cause);<a name="line.1727"></a>
+<span class="sourceLineNo">1728</span>        } finally {<a name="line.1728"></a>
+<span class="sourceLineNo">1729</span>          storeCloserThreadPool.shutdownNow();<a name="line.1729"></a>
+<span class="sourceLineNo">1730</span>        }<a name="line.1730"></a>
+<span class="sourceLineNo">1731</span>      }<a name="line.1731"></a>
+<span class="sourceLineNo">1732</span><a name="line.1732"></a>
+<span class="sourceLineNo">1733</span>      status.setStatus("Writing region close event to WAL");<a name="line.1733"></a>
+<span class="sourceLineNo">1734</span>      // Always write close marker to wal even for read only table. This is not a big problem as we<a name="line.1734"></a>
+<span class="sourceLineNo">1735</span>      // do not write any data into the region.<a name="line.1735"></a>
+<span class="sourceLineNo">1736</span>      if (!abort &amp;&amp; wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.1736"></a>
+<span class="sourceLineNo">1737</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.1737"></a>
+<span class="sourceLineNo">1738</span>        writeRegionCloseMarker(wal);<a name="line.1738"></a>
+<span class="sourceLineNo">1739</span>      }<a name="line.1739"></a>
+<span class="sourceLineNo">1740</span><a name="line.1740"></a>
+<span class="sourceLineNo">1741</span>      this.closed.set(true);<a name="line.1741"></a>
+<span class="sourceLineNo">1742</span>      if (!canFlush) {<a name="line.1742"></a>
+<span class="sourceLineNo">1743</span>        decrMemStoreSize(this.memStoreSizing.getMemStoreSize());<a name="line.1743"></a>
+<span class="sourceLineNo">1744</span>      } else if (this.memStoreSizing.getDataSize() != 0) {<a name="line.1744"></a>
+<span class="sourceLineNo">1745</span>        LOG.error("Memstore data size is {}", this.memStoreSizing.getDataSize());<a name="line.1745"></a>
+<span class="sourceLineNo">1746</span>      }<a name="line.1746"></a>
+<span class="sourceLineNo">1747</span>      if (coprocessorHost != null) {<a name="line.1747"></a>
+<span class="sourceLineNo">1748</span>        status.setStatus("Running coprocessor post-close hooks");<a name="line.1748"></a>
+<span class="sourceLineNo">1749</span>        this.coprocessorHost.postClose(abort);<a name="line.1749"></a>
 <span class="sourceLineNo">1750</span>      }<a name="line.1750"></a>
-<span class="sourceLineNo">1751</span>      if (this.metricsRegionWrapper != null) {<a name="line.1751"></a>
-<span class="sourceLineNo">1752</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1752"></a>
+<span class="sourceLineNo">1751</span>      if (this.metricsRegion != null) {<a name="line.1751"></a>
+<span class="sourceLineNo">1752</span>        this.metricsRegion.close();<a name="line.1752"></a>
 <span class="sourceLineNo">1753</span>      }<a name="line.1753"></a>
-<span class="sourceLineNo">1754</span>      status.markComplete("Closed");<a name="line.1754"></a>
-<span class="sourceLineNo">1755</span>      LOG.info("Closed " + this);<a name="line.1755"></a>
-<span class="sourceLineNo">1756</span>      return result;<a name="line.1756"></a>
-<span class="sourceLineNo">1757</span>    } finally {<a name="line.1757"></a>
-<span class="sourceLineNo">1758</span>      lock.writeLock().unlock();<a name="line.1758"></a>
-<span class="sourceLineNo">1759</span>    }<a name="line.1759"></a>
-<span class="sourceLineNo">1760</span>  }<a name="line.1760"></a>
-<span class="sourceLineNo">1761</span><a name="line.1761"></a>
-<span class="sourceLineNo">1762</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1762"></a>
-<span class="sourceLineNo">1763</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1763"></a>
-<span class="sourceLineNo">1764</span>  // Phoenix needs.<a name="line.1764"></a>
-<span class="sourceLineNo">1765</span>  public void waitForFlushesAndCompactions() {<a name="line.1765"></a>
-<span class="sourceLineNo">1766</span>    synchronized (writestate) {<a name="line.1766"></a>
-<span class="sourceLineNo">1767</span>      if (this.writestate.readOnly) {<a name="line.1767"></a>
-<span class="sourceLineNo">1768</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1768"></a>
-<span class="sourceLineNo">1769</span>        // region is a secondary replica).<a name="line.1769"></a>
-<span class="sourceLineNo">1770</span>        return;<a name="line.1770"></a>
-<span class="sourceLineNo">1771</span>      }<a name="line.1771"></a>
-<span class="sourceLineNo">1772</span>      boolean interrupted = false;<a name="line.1772"></a>
-<span class="sourceLineNo">1773</span>      try {<a name="line.1773"></a>
-<span class="sourceLineNo">1774</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1774"></a>
-<span class="sourceLineNo">1775</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1775"></a>
-<span class="sourceLineNo">1776</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1776"></a>
-<span class="sourceLineNo">1777</span>          try {<a name="line.1777"></a>
-<span class="sourceLineNo">1778</span>            writestate.wait();<a name="line.1778"></a>
-<span class="sourceLineNo">1779</span>          } catch (InterruptedException iex) {<a name="line.1779"></a>
-<span class="sourceLineNo">1780</span>            // essentially ignore and propagate the interrupt back up<a name="line.1780"></a>
-<span class="sourceLineNo">1781</span>            LOG.warn("Interrupted while waiting");<a name="line.1781"></a>
-<span class="sourceLineNo">1782</span>            interrupted = true;<a name="line.1782"></a>
-<span class="sourceLineNo">1783</span>            break;<a name="line.1783"></a>
-<span class="sourceLineNo">1784</span>          }<a name="line.1784"></a>
-<span class="sourceLineNo">1785</span>        }<a name="line.1785"></a>
-<span class="sourceLineNo">1786</span>      } finally {<a name="line.1786"></a>
-<span class="sourceLineNo">1787</span>        if (interrupted) {<a name="line.1787"></a>
-<span class="sourceLineNo">1788</span>          Thread.currentThread().interrupt();<a name="line.1788"></a>
-<span class="sourceLineNo">1789</span>        }<a name="line.1789"></a>
-<span class="sourceLineNo">1790</span>      }<a name="line.1790"></a>
-<span class="sourceLineNo">1791</span>    }<a name="line.1791"></a>
-<span class="sourceLineNo">1792</span>  }<a name="line.1792"></a>
-<span class="sourceLineNo">1793</span><a name="line.1793"></a>
-<span class="sourceLineNo">1794</span>  /**<a name="line.1794"></a>
-<span class="sourceLineNo">1795</span>   * Wait for all current flushes of the region to complete<a name="line.1795"></a>
-<span class="sourceLineNo">1796</span>   */<a name="line.1796"></a>
-<span class="sourceLineNo">1797</span>  public void waitForFlushes() {<a name="line.1797"></a>
-<span class="sourceLineNo">1798</span>    waitForFlushes(0);// Unbound wait<a name="line.1798"></a>
-<span class="sourceLineNo">1799</span>  }<a name="line.1799"></a>
-<span class="sourceLineNo">1800</span><a name="line.1800"></a>
-<span class="sourceLineNo">1801</span>  @Override<a name="line.1801"></a>
-<span class="sourceLineNo">1802</span>  public boolean waitForFlushes(long timeout) {<a name="line.1802"></a>
-<span class="sourceLineNo">1803</span>    synchronized (writestate) {<a name="line.1803"></a>
-<span class="sourceLineNo">1804</span>      if (this.writestate.readOnly) {<a name="line.1804"></a>
-<span class="sourceLineNo">1805</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1805"></a>
-<span class="sourceLineNo">1806</span>        // region is a secondary replica).<a name="line.1806"></a>
-<span class="sourceLineNo">1807</span>        return true;<a name="line.1807"></a>
-<span class="sourceLineNo">1808</span>      }<a name="line.1808"></a>
-<span class="sourceLineNo">1809</span>      if (!writestate.flushing) return true;<a name="line.1809"></a>
-<span class="sourceLineNo">1810</span>      long start = System.currentTimeMillis();<a name="line.1810"></a>
-<span class="sourceLineNo">1811</span>      long duration = 0;<a name="line.1811"></a>
-<span class="sourceLineNo">1812</span>      boolean interrupted = false;<a name="line.1812"></a>
-<span class="sourceLineNo">1813</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1813"></a>
-<span class="sourceLineNo">1814</span>      try {<a name="line.1814"></a>
-<span class="sourceLineNo">1815</span>        while (writestate.flushing) {<a name="line.1815"></a>
-<span class="sourceLineNo">1816</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1816"></a>
-<span class="sourceLineNo">1817</span>          try {<a name="line.1817"></a>
-<span class="sourceLineNo">1818</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1818"></a>
-<span class="sourceLineNo">1819</span>            writestate.wait(toWait);<a name="line.1819"></a>
-<span class="sourceLineNo">1820</span>          } catch (InterruptedException iex) {<a name="line.1820"></a>
-<span class="sourceLineNo">1821</span>            // essentially ignore and propagate the interrupt back up<a name="line.1821"></a>
-<span class="sourceLineNo">1822</span>            LOG.warn("Interrupted while waiting");<a name="line.1822"></a>
-<span class="sourceLineNo">1823</span>            interrupted = true;<a name="line.1823"></a>
-<span class="sourceLineNo">1824</span>            break;<a name="line.1824"></a>
-<span class="sourceLineNo">1825</span>          } finally {<a name="line.1825"></a>
-<span class="sourceLineNo">1826</span>            duration = System.currentTimeMillis() - start;<a name="line.1826"></a>
-<span class="sourceLineNo">1827</span>          }<a name="line.1827"></a>
-<span class="sourceLineNo">1828</span>        }<a name="line.1828"></a>
-<span class="sourceLineNo">1829</span>      } finally {<a name="line.1829"></a>
-<span class="sourceLineNo">1830</span>        if (interrupted) {<a name="line.1830"></a>
-<span class="sourceLineNo">1831</span>          Thread.currentThread().interrupt();<a name="line.1831"></a>
-<span class="sourceLineNo">1832</span>        }<a name="line.1832"></a>
-<span class="sourceLineNo">1833</span>      }<a name="line.1833"></a>
-<span class="sourceLineNo">1834</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1834"></a>
-<span class="sourceLineNo">1835</span>      return !(writestate.flushing);<a name="line.1835"></a>
-<span class="sourceLineNo">1836</span>    }<a name="line.1836"></a>
-<span class="sourceLineNo">1837</span>  }<a name="line.1837"></a>
-<span class="sourceLineNo">1838</span><a name="line.1838"></a>
-<span class="sourceLineNo">1839</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1839"></a>
-<span class="sourceLineNo">1840</span>      final String threadNamePrefix) {<a name="line.1840"></a>
-<span class="sourceLineNo">1841</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1841"></a>
-<span class="sourceLineNo">1842</span>    int maxThreads = Math.min(numStores,<a name="line.1842"></a>
-<span class="sourceLineNo">1843</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1843"></a>
-<span class="sourceLineNo">1844</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1844"></a>
-<span class="sourceLineNo">1845</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1845"></a>
-<span class="sourceLineNo">1846</span>  }<a name="line.1846"></a>
-<span class="sourceLineNo">1847</span><a name="line.1847"></a>
-<span class="sourceLineNo">1848</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1848"></a>
-<span class="sourceLineNo">1849</span>      final String threadNamePrefix) {<a name="line.1849"></a>
-<span class="sourceLineNo">1850</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1850"></a>
-<span class="sourceLineNo">1851</span>    int maxThreads = Math.max(1,<a name="line.1851"></a>
-<span class="sourceLineNo">1852</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1852"></a>
-<span class="sourceLineNo">1853</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1853"></a>
-<span class="sourceLineNo">1854</span>            / numStores);<a name="line.1854"></a>
-<span class="sourceLineNo">1855</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1855"></a>
-<span class="sourceLineNo">1856</span>  }<a name="line.1856"></a>
-<span class="sourceLineNo">1857</span><a name="line.1857"></a>
-<span class="sourceLineNo">1858</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1858"></a>
-<span class="sourceLineNo">1859</span>      final String threadNamePrefix) {<a name="line.1859"></a>
-<span class="sourceLineNo">1860</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1860"></a>
-<span class="sourceLineNo">1861</span>      new ThreadFactory() {<a name="line.1861"></a>
-<span class="sourceLineNo">1862</span>        private int count = 1;<a name="line.1862"></a>
-<span class="sourceLineNo">1863</span><a name="line.1863"></a>
-<span class="sourceLineNo">1864</span>        @Override<a name="line.1864"></a>
-<span class="sourceLineNo">1865</span>        public Thread newThread(Runnable r) {<a name="line.1865"></a>
-<span class="sourceLineNo">1866</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1866"></a>
-<span class="sourceLineNo">1867</span>        }<a name="line.1867"></a>
-<span class="sourceLineNo">1868</span>      });<a name="line.1868"></a>
-<span class="sourceLineNo">1869</span>  }<a name="line.1869"></a>
-<span class="sourceLineNo">1870</span><a name="line.1870"></a>
-<span class="sourceLineNo">1871</span>   /**<a name="line.1871"></a>
-<span class="sourceLineNo">1872</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1872"></a>
-<span class="sourceLineNo">1873</span>    */<a name="line.1873"></a>
-<span class="sourceLineNo">1874</span>  private boolean worthPreFlushing() {<a name="line.1874"></a>
-<span class="sourceLineNo">1875</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1875"></a>
-<span class="sourceLineNo">1876</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1876"></a>
-<span class="sourceLineNo">1877</span>  }<a name="line.1877"></a>
-<span class="sourceLineNo">1878</span><a name="line.1878"></a>
-<span class="sourceLineNo">1879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1879"></a>
-<span class="sourceLineNo">1880</span>  // HRegion accessors<a name="line.1880"></a>
-<span class="sourceLineNo">1881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1881"></a>
-<span class="sourceLineNo">1882</span><a name="line.1882"></a>
-<span class="sourceLineNo">1883</span>  @Override<a name="line.1883"></a>
-<span class="sourceLineNo">1884</span>  public TableDescriptor getTableDescriptor() {<a name="line.1884"></a>
-<span class="sourceLineNo">1885</span>    return this.htableDescriptor;<a name="line.1885"></a>
-<span class="sourceLineNo">1886</span>  }<a name="line.1886"></a>
-<span class="sourceLineNo">1887</span><a name="line.1887"></a>
-<span class="sourceLineNo">1888</span>  @VisibleForTesting<a name="line.1888"></a>
-<span class="sourceLineNo">1889</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1889"></a>
-<span class="sourceLineNo">1890</span>    htableDescriptor = desc;<a name="line.1890"></a>
-<span class="sourceLineNo">1891</span>  }<a name="line.1891"></a>
-<span class="sourceLineNo">1892</span><a name="line.1892"></a>
-<span class="sourceLineNo">1893</span>  /** @return WAL in use for this region */<a name="line.1893"></a>
-<span class="sourceLineNo">1894</span>  public WAL getWAL() {<a name="line.1894"></a>
-<span class="sourceLineNo">1895</span>    return this.wal;<a name="line.1895"></a>
-<span class="sourceLineNo">1896</span>  }<a name="line.1896"></a>
-<span class="sourceLineNo">1897</span><a name="line.1897"></a>
-<span class="sourceLineNo">1898</span>  public BlockCache getBlockCache() {<a name="line.1898"></a>
-<span class="sourceLineNo">1899</span>    return this.blockCache;<a name="line.1899"></a>
-<span class="sourceLineNo">1900</span>  }<a name="line.1900"></a>
-<span class="sourceLineNo">1901</span><a name="line.1901"></a>
-<span class="sourceLineNo">1902</span>  /**<a name="line.1902"></a>
-<span class="sourceLineNo">1903</span>   * Only used for unit test which doesn't start region server.<a name="line.1903"></a>
-<span class="sourceLineNo">1904</span>   */<a name="line.1904"></a>
-<span class="sourceLineNo">1905</span>  @VisibleForTesting<a name="line.1905"></a>
-<span class="sourceLineNo">1906</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1906"></a>
-<span class="sourceLineNo">1907</span>    this.blockCache = blockCache;<a name="line.1907"></a>
-<span class="sourceLineNo">1908</span>  }<a name="line.1908"></a>
-<span class="sourceLineNo">1909</span><a name="line.1909"></a>
-<span class="sourceLineNo">1910</span>  public MobFileCache getMobFileCache() {<a name="line.1910"></a>
-<span class="sourceLineNo">1911</span>    return this.mobFileCache;<a name="line.1911"></a>
-<span class="sourceLineNo">1912</span>  }<a name="line.1912"></a>
-<span class="sourceLineNo">1913</span><a name="line.1913"></a>
-<span class="sourceLineNo">1914</span>  /**<a name="line.1914"></a>
-<span class="sourceLineNo">1915</span>   * Only used for unit test which doesn't start region server.<a name="line.1915"></a>
-<span class="sourceLineNo">1916</span>   */<a name="line.1916"></a>
-<span class="sourceLineNo">1917</span>  @VisibleForTesting<a name="line.1917"></a>
-<span class="sourceLineNo">1918</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1918"></a>
-<span class="sourceLineNo">1919</span>    this.mobFileCache = mobFileCache;<a name="line.1919"></a>
-<span class="sourceLineNo">1920</span>  }<a name="line.1920"></a>
-<span class="sourceLineNo">1921</span><a name="line.1921"></a>
-<span class="sourceLineNo">1922</span>  /**<a name="line.1922"></a>
-<span class="sourceLineNo">1923</span>   * @return split policy for this region.<a name="line.1923"></a>
-<span class="sourceLineNo">1924</span>   */<a name="line.1924"></a>
-<span class="sourceLineNo">1925</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1925"></a>
-<span class="sourceLineNo">1926</span>    return this.splitPolicy;<a name="line.1926"></a>
-<span class="sourceLineNo">1927</span>  }<a name="line.1927"></a>
-<span class="sourceLineNo">1928</span><a name="line.1928"></a>
-<span class="sourceLineNo">1929</span>  /**<a name="line.1929"></a>
-<span class="sourceLineNo">1930</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1930"></a>
-<span class="sourceLineNo">1931</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1931"></a>
-<span class="sourceLineNo">1932</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1932"></a>
-<span class="sourceLineNo">1933</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1933"></a>
-<span class="sourceLineNo">1934</span>   * @return Configuration object<a name="line.1934"></a>
-<span class="sourceLineNo">1935</span>   */<a name="line.1935"></a>
-<span class="sourceLineNo">1936</span>  Configuration getBaseConf() {<a name="line.1936"></a>
-<span class="sourceLineNo">1937</span>    return this.baseConf;<a name="line.1937"></a>
-<span class="sourceLineNo">1938</span>  }<a name="line.1938"></a>
-<span class="sourceLineNo">1939</span><a name="line.1939"></a>
-<span class="sourceLineNo">1940</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1940"></a>
-<span class="sourceLineNo">1941</span>  public FileSystem getFilesystem() {<a name="line.1941"></a>
-<span class="sourceLineNo">1942</span>    return fs.getFileSystem();<a name="line.1942"></a>
-<span class="sourceLineNo">1943</span>  }<a name="line.1943"></a>
-<span class="sourceLineNo">1944</span><a name="line.1944"></a>
-<span class="sourceLineNo">1945</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1945"></a>
-<span class="sourceLineNo">1946</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1946"></a>
-<span class="sourceLineNo">1947</span>    return this.fs;<a name="line.1947"></a>
-<span class="sourceLineNo">1948</span>  }<a name="line.1948"></a>
-<span class="sourceLineNo">1949</span><a name="line.1949"></a>
-<span class="sourceLineNo">1950</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1950"></a>
-<span class="sourceLineNo">1951</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1951"></a>
-<span class="sourceLineNo">1952</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1952"></a>
-<span class="sourceLineNo">1953</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1953"></a>
-<span class="sourceLineNo">1954</span>  }<a name="line.1954"></a>
-<span class="sourceLineNo">1955</span><a name="line.1955"></a>
-<span class="sourceLineNo">1956</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1956"></a>
-<span class="sourceLineNo">1957</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1957"></a>
-<span class="sourceLineNo">1958</span>    if (walFS == null) {<a name="line.1958"></a>
-<span class="sourceLineNo">1959</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1959"></a>
-<span class="sourceLineNo">1960</span>    }<a name="line.1960"></a>
-<span class="sourceLineNo">1961</span>    return walFS;<a name="line.1961"></a>
-<span class="sourceLineNo">1962</span>  }<a name="line.1962"></a>
-<span class="sourceLineNo">1963</span><a name="line.1963"></a>
-<span class="sourceLineNo">1964</span>  /**<a name="line.1964"></a>
-<span class="sourceLineNo">1965</span>   * @return the Region directory under WALRootDirectory<a name="line.1965"></a>
-<span class="sourceLineNo">1966</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1966"></a>
-<span class="sourceLineNo">1967</span>   */<a name="line.1967"></a>
-<span class="sourceLineNo">1968</span>  @VisibleForTesting<a name="line.1968"></a>
-<span class="sourceLineNo">1969</span>  public Path getWALRegionDir() throws IOException {<a name="line.1969"></a>
-<span class="sourceLineNo">1970</span>    if (regionDir == null) {<a name="line.1970"></a>
-<span class="sourceLineNo">1971</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1971"></a>
-<span class="sourceLineNo">1972</span>          getRegionInfo().getEncodedName());<a name="line.1972"></a>
-<span class="sourceLineNo">1973</span>    }<a name="line.1973"></a>
-<span class="sourceLineNo">1974</span>    return regionDir;<a name="line.1974"></a>
-<span class="sourceLineNo">1975</span>  }<a name="line.1975"></a>
-<span class="sourceLineNo">1976</span><a name="line.1976"></a>
-<span class="sourceLineNo">1977</span>  @Override<a name="line.1977"></a>
-<span class="sourceLineNo">1978</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1978"></a>
-<span class="sourceLineNo">1979</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1979"></a>
-<span class="sourceLineNo">1980</span>  }<a name="line.1980"></a>
-<span class="sourceLineNo">1981</span><a name="line.1981"></a>
-<span class="sourceLineNo">1982</span>  @Override<a name="line.1982"></a>
-<span class="sourceLineNo">1983</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1983"></a>
-<span class="sourceLineNo">1984</span>    long result = Long.MAX_VALUE;<a name="line.1984"></a>
-<span class="sourceLineNo">1985</span>    for (HStore store : stores.values()) {<a name="line.1985"></a>
-<span class="sourceLineNo">1986</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1986"></a>
-<span class="sourceLineNo">1987</span>      if (storeFiles == null) {<a name="line.1987"></a>
-<span class="sourceLineNo">1988</span>        continue;<a name="line.1988"></a>
-<span class="sourceLineNo">1989</span>      }<a name="line.1989"></a>
-<span class="sourceLineNo">1990</span>      for (HStoreFile file : storeFiles) {<a name="line.1990"></a>
-<span class="sourceLineNo">1991</span>        StoreFileReader sfReader = file.getReader();<a name="line.1991"></a>
-<span class="sourceLineNo">1992</span>        if (sfReader == null) {<a name="line.1992"></a>
-<span class="sourceLineNo">1993</span>          continue;<a name="line.1993"></a>
-<span class="sourceLineNo">1994</span>        }<a name="line.1994"></a>
-<span class="sourceLineNo">1995</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1995"></a>
-<span class="sourceLineNo">1996</span>        if (reader == null) {<a name="line.1996"></a>
-<span class="sourceLineNo">1997</span>          continue;<a name="line.1997"></a>
-<span class="sourceLineNo">1998</span>        }<a name="line.1998"></a>
-<span class="sourceLineNo">1999</span>        if (majorCompactionOnly) {<a name="line.1999"></a>
-<span class="sourceLineNo">2000</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2000"></a>
-<span class="sourceLineNo">2001</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2001"></a>
-<span class="sourceLineNo">2002</span>            continue;<a name="line.2002"></a>
-<span class="sourceLineNo">2003</span>          }<a name="line.2003"></a>
-<span class="sourceLineNo">2004</span>        }<a name="line.2004"></a>
-<span class="sourceLineNo">2005</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2005"></a>
-<span class="sourceLineNo">2006</span>      }<a name="line.2006"></a>
-<span class="sourceLineNo">2007</span>    }<a name="line.2007"></a>
-<span class="sourceLineNo">2008</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2008"></a>
-<span class="sourceLineNo">2009</span>  }<a name="line.2009"></a>
-<span class="sourceLineNo">2010</span><a name="line.2010"></a>
-<span class="sourceLineNo">2011</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2011"></a>
-<span class="sourceLineNo">2012</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2012"></a>
-<span class="sourceLineNo">2013</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2013"></a>
-<span class="sourceLineNo">2014</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2014"></a>
-<span class="sourceLineNo">2015</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2015"></a>
-<span class="sourceLineNo">2016</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2016"></a>
-<span class="sourceLineNo">2017</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2017"></a>
-<span class="sourceLineNo">2018</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2018"></a>
-<span class="sourceLineNo">2019</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2019"></a>
-<span class="sourceLineNo">2020</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2020"></a>
-<span class="sourceLineNo">2021</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2021"></a>
-<span class="sourceLineNo">2022</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2022"></a>
-<span class="sourceLineNo">2023</span>    }<a name="line.2023"></a>
-<span class="sourceLineNo">2024</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2024"></a>
-<span class="sourceLineNo">2025</span>  }<a name="line.2025"></a>
-<span class="sourceLineNo">2026</span><a name="line.2026"></a>
-<span class="sourceLineNo">2027</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2027"></a>
-<span class="sourceLineNo">2028</span>  // HRegion maintenance.<a name="line.2028"></a>
-<span class="sourceLineNo">2029</span>  //<a name="line.2029"></a>
-<span class="sourceLineNo">2030</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2030"></a>
-<span class="sourceLineNo">2031</span>  // upkeep.<a name="line.2031"></a>
-<span class="sourceLineNo">2032</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2032"></a>
-<span class="sourceLineNo">2033</span>  /**<a name="line.2033"></a>
-<span class="sourceLineNo">2034</span>   * Do preparation for pending compaction.<a name="line.2034"></a>
-<span class="sourceLineNo">2035</span>   * @throws IOException<a name="line.2035"></a>
-<span class="sourceLineNo">2036</span>   */<a name="line.2036"></a>
-<span class="sourceLineNo">2037</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2037"></a>
-<span class="sourceLineNo">2038</span>  }<a name="line.2038"></a>
-<span class="sourceLineNo">2039</span><a name="line.2039"></a>
-<span class="sourceLineNo">2040</span>  /**<a name="line.2040"></a>
-<span class="sourceLineNo">2041</span>   * Synchronously compact all stores in the region.<a name="line.2041"></a>
-<span class="sourceLineNo">2042</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2042"></a>
-<span class="sourceLineNo">2043</span>   * time-sensitive thread.<a name="line.2043"></a>
-<span class="sourceLineNo">2044</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2044"></a>
-<span class="sourceLineNo">2045</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2045"></a>
-<span class="sourceLineNo">2046</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2046"></a>
-<span class="sourceLineNo">2047</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2047"></a>
-<span class="sourceLineNo">2048</span>   * you are doing.<a name="line.2048"></a>
-<span class="sourceLineNo">2049</span>   *<a name="line.2049"></a>
-<span class="sourceLineNo">2050</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2050"></a>
-<span class="sourceLineNo">2051</span>   * @throws IOException<a name="line.2051"></a>
-<span class="sourceLineNo">2052</span>   */<a name="line.2052"></a>
-<span class="sourceLineNo">2053</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2053"></a>
-<span class="sourceLineNo">2054</span>    if (majorCompaction) {<a name="line.2054"></a>
-<span class="sourceLineNo">2055</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2055"></a>
-<span class="sourceLineNo">2056</span>    }<a name="line.2056"></a>
-<span class="sourceLineNo">2057</span>    for (HStore s : stores.values()) {<a name="line.2057"></a>
-<span class="sourceLineNo">2058</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2058"></a>
-<span class="sourceLineNo">2059</span>      if (compaction.isPresent()) {<a name="line.2059"></a>
-<span class="sourceLineNo">2060</span>        ThroughputController controller = null;<a name="line.2060"></a>
-<span class="sourceLineNo">2061</span>        if (rsServices != null) {<a name="line.2061"></a>
-<span class="sourceLineNo">2062</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2062"></a>
-<span class="sourceLineNo">2063</span>        }<a name="line.2063"></a>
-<span class="sourceLineNo">2064</span>        if (controller == null) {<a name="line.2064"></a>
-<span class="sourceLineNo">2065</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2065"></a>
+<span class="sourceLineNo">1754</span>      if (this.metricsRegionWrapper != null) {<a name="line.1754"></a>
+<span class="sourceLineNo">1755</span>        Closeables.close(this.metricsRegionWrapper, true);<a name="line.1755"></a>
+<span class="sourceLineNo">1756</span>      }<a name="line.1756"></a>
+<span class="sourceLineNo">1757</span>      status.markComplete("Closed");<a name="line.1757"></a>
+<span class="sourceLineNo">1758</span>      LOG.info("Closed " + this);<a name="line.1758"></a>
+<span class="sourceLineNo">1759</span>      return result;<a name="line.1759"></a>
+<span class="sourceLineNo">1760</span>    } finally {<a name="line.1760"></a>
+<span class="sourceLineNo">1761</span>      lock.writeLock().unlock();<a name="line.1761"></a>
+<span class="sourceLineNo">1762</span>    }<a name="line.1762"></a>
+<span class="sourceLineNo">1763</span>  }<a name="line.1763"></a>
+<span class="sourceLineNo">1764</span><a name="line.1764"></a>
+<span class="sourceLineNo">1765</span>  /** Wait for all current flushes and compactions of the region to complete */<a name="line.1765"></a>
+<span class="sourceLineNo">1766</span>  // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for<a name="line.1766"></a>
+<span class="sourceLineNo">1767</span>  // Phoenix needs.<a name="line.1767"></a>
+<span class="sourceLineNo">1768</span>  public void waitForFlushesAndCompactions() {<a name="line.1768"></a>
+<span class="sourceLineNo">1769</span>    synchronized (writestate) {<a name="line.1769"></a>
+<span class="sourceLineNo">1770</span>      if (this.writestate.readOnly) {<a name="line.1770"></a>
+<span class="sourceLineNo">1771</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1771"></a>
+<span class="sourceLineNo">1772</span>        // region is a secondary replica).<a name="line.1772"></a>
+<span class="sourceLineNo">1773</span>        return;<a name="line.1773"></a>
+<span class="sourceLineNo">1774</span>      }<a name="line.1774"></a>
+<span class="sourceLineNo">1775</span>      boolean interrupted = false;<a name="line.1775"></a>
+<span class="sourceLineNo">1776</span>      try {<a name="line.1776"></a>
+<span class="sourceLineNo">1777</span>        while (writestate.compacting.get() &gt; 0 || writestate.flushing) {<a name="line.1777"></a>
+<span class="sourceLineNo">1778</span>          LOG.debug("waiting for " + writestate.compacting + " compactions"<a name="line.1778"></a>
+<span class="sourceLineNo">1779</span>            + (writestate.flushing ? " &amp; cache flush" : "") + " to complete for region " + this);<a name="line.1779"></a>
+<span class="sourceLineNo">1780</span>          try {<a name="line.1780"></a>
+<span class="sourceLineNo">1781</span>            writestate.wait();<a name="line.1781"></a>
+<span class="sourceLineNo">1782</span>          } catch (InterruptedException iex) {<a name="line.1782"></a>
+<span class="sourceLineNo">1783</span>            // essentially ignore and propagate the interrupt back up<a name="line.1783"></a>
+<span class="sourceLineNo">1784</span>            LOG.warn("Interrupted while waiting");<a name="line.1784"></a>
+<span class="sourceLineNo">1785</span>            interrupted = true;<a name="line.1785"></a>
+<span class="sourceLineNo">1786</span>            break;<a name="line.1786"></a>
+<span class="sourceLineNo">1787</span>          }<a name="line.1787"></a>
+<span class="sourceLineNo">1788</span>        }<a name="line.1788"></a>
+<span class="sourceLineNo">1789</span>      } finally {<a name="line.1789"></a>
+<span class="sourceLineNo">1790</span>        if (interrupted) {<a name="line.1790"></a>
+<span class="sourceLineNo">1791</span>          Thread.currentThread().interrupt();<a name="line.1791"></a>
+<span class="sourceLineNo">1792</span>        }<a name="line.1792"></a>
+<span class="sourceLineNo">1793</span>      }<a name="line.1793"></a>
+<span class="sourceLineNo">1794</span>    }<a name="line.1794"></a>
+<span class="sourceLineNo">1795</span>  }<a name="line.1795"></a>
+<span class="sourceLineNo">1796</span><a name="line.1796"></a>
+<span class="sourceLineNo">1797</span>  /**<a name="line.1797"></a>
+<span class="sourceLineNo">1798</span>   * Wait for all current flushes of the region to complete<a name="line.1798"></a>
+<span class="sourceLineNo">1799</span>   */<a name="line.1799"></a>
+<span class="sourceLineNo">1800</span>  public void waitForFlushes() {<a name="line.1800"></a>
+<span class="sourceLineNo">1801</span>    waitForFlushes(0);// Unbound wait<a name="line.1801"></a>
+<span class="sourceLineNo">1802</span>  }<a name="line.1802"></a>
+<span class="sourceLineNo">1803</span><a name="line.1803"></a>
+<span class="sourceLineNo">1804</span>  @Override<a name="line.1804"></a>
+<span class="sourceLineNo">1805</span>  public boolean waitForFlushes(long timeout) {<a name="line.1805"></a>
+<span class="sourceLineNo">1806</span>    synchronized (writestate) {<a name="line.1806"></a>
+<span class="sourceLineNo">1807</span>      if (this.writestate.readOnly) {<a name="line.1807"></a>
+<span class="sourceLineNo">1808</span>        // we should not wait for replayed flushed if we are read only (for example in case the<a name="line.1808"></a>
+<span class="sourceLineNo">1809</span>        // region is a secondary replica).<a name="line.1809"></a>
+<span class="sourceLineNo">1810</span>        return true;<a name="line.1810"></a>
+<span class="sourceLineNo">1811</span>      }<a name="line.1811"></a>
+<span class="sourceLineNo">1812</span>      if (!writestate.flushing) return true;<a name="line.1812"></a>
+<span class="sourceLineNo">1813</span>      long start = System.currentTimeMillis();<a name="line.1813"></a>
+<span class="sourceLineNo">1814</span>      long duration = 0;<a name="line.1814"></a>
+<span class="sourceLineNo">1815</span>      boolean interrupted = false;<a name="line.1815"></a>
+<span class="sourceLineNo">1816</span>      LOG.debug("waiting for cache flush to complete for region " + this);<a name="line.1816"></a>
+<span class="sourceLineNo">1817</span>      try {<a name="line.1817"></a>
+<span class="sourceLineNo">1818</span>        while (writestate.flushing) {<a name="line.1818"></a>
+<span class="sourceLineNo">1819</span>          if (timeout &gt; 0 &amp;&amp; duration &gt;= timeout) break;<a name="line.1819"></a>
+<span class="sourceLineNo">1820</span>          try {<a name="line.1820"></a>
+<span class="sourceLineNo">1821</span>            long toWait = timeout == 0 ? 0 : (timeout - duration);<a name="line.1821"></a>
+<span class="sourceLineNo">1822</span>            writestate.wait(toWait);<a name="line.1822"></a>
+<span class="sourceLineNo">1823</span>          } catch (InterruptedException iex) {<a name="line.1823"></a>
+<span class="sourceLineNo">1824</span>            // essentially ignore and propagate the interrupt back up<a name="line.1824"></a>
+<span class="sourceLineNo">1825</span>            LOG.warn("Interrupted while waiting");<a name="line.1825"></a>
+<span class="sourceLineNo">1826</span>            interrupted = true;<a name="line.1826"></a>
+<span class="sourceLineNo">1827</span>            break;<a name="line.1827"></a>
+<span class="sourceLineNo">1828</span>          } finally {<a name="line.1828"></a>
+<span class="sourceLineNo">1829</span>            duration = System.currentTimeMillis() - start;<a name="line.1829"></a>
+<span class="sourceLineNo">1830</span>          }<a name="line.1830"></a>
+<span class="sourceLineNo">1831</span>        }<a name="line.1831"></a>
+<span class="sourceLineNo">1832</span>      } finally {<a name="line.1832"></a>
+<span class="sourceLineNo">1833</span>        if (interrupted) {<a name="line.1833"></a>
+<span class="sourceLineNo">1834</span>          Thread.currentThread().interrupt();<a name="line.1834"></a>
+<span class="sourceLineNo">1835</span>        }<a name="line.1835"></a>
+<span class="sourceLineNo">1836</span>      }<a name="line.1836"></a>
+<span class="sourceLineNo">1837</span>      LOG.debug("Waited " + duration + " ms for flush to complete");<a name="line.1837"></a>
+<span class="sourceLineNo">1838</span>      return !(writestate.flushing);<a name="line.1838"></a>
+<span class="sourceLineNo">1839</span>    }<a name="line.1839"></a>
+<span class="sourceLineNo">1840</span>  }<a name="line.1840"></a>
+<span class="sourceLineNo">1841</span><a name="line.1841"></a>
+<span class="sourceLineNo">1842</span>  protected ThreadPoolExecutor getStoreOpenAndCloseThreadPool(<a name="line.1842"></a>
+<span class="sourceLineNo">1843</span>      final String threadNamePrefix) {<a name="line.1843"></a>
+<span class="sourceLineNo">1844</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1844"></a>
+<span class="sourceLineNo">1845</span>    int maxThreads = Math.min(numStores,<a name="line.1845"></a>
+<span class="sourceLineNo">1846</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1846"></a>
+<span class="sourceLineNo">1847</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX));<a name="line.1847"></a>
+<span class="sourceLineNo">1848</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1848"></a>
+<span class="sourceLineNo">1849</span>  }<a name="line.1849"></a>
+<span class="sourceLineNo">1850</span><a name="line.1850"></a>
+<span class="sourceLineNo">1851</span>  protected ThreadPoolExecutor getStoreFileOpenAndCloseThreadPool(<a name="line.1851"></a>
+<span class="sourceLineNo">1852</span>      final String threadNamePrefix) {<a name="line.1852"></a>
+<span class="sourceLineNo">1853</span>    int numStores = Math.max(1, this.htableDescriptor.getColumnFamilyCount());<a name="line.1853"></a>
+<span class="sourceLineNo">1854</span>    int maxThreads = Math.max(1,<a name="line.1854"></a>
+<span class="sourceLineNo">1855</span>        conf.getInt(HConstants.HSTORE_OPEN_AND_CLOSE_THREADS_MAX,<a name="line.1855"></a>
+<span class="sourceLineNo">1856</span>            HConstants.DEFAULT_HSTORE_OPEN_AND_CLOSE_THREADS_MAX)<a name="line.1856"></a>
+<span class="sourceLineNo">1857</span>            / numStores);<a name="line.1857"></a>
+<span class="sourceLineNo">1858</span>    return getOpenAndCloseThreadPool(maxThreads, threadNamePrefix);<a name="line.1858"></a>
+<span class="sourceLineNo">1859</span>  }<a name="line.1859"></a>
+<span class="sourceLineNo">1860</span><a name="line.1860"></a>
+<span class="sourceLineNo">1861</span>  static ThreadPoolExecutor getOpenAndCloseThreadPool(int maxThreads,<a name="line.1861"></a>
+<span class="sourceLineNo">1862</span>      final String threadNamePrefix) {<a name="line.1862"></a>
+<span class="sourceLineNo">1863</span>    return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,<a name="line.1863"></a>
+<span class="sourceLineNo">1864</span>      new ThreadFactory() {<a name="line.1864"></a>
+<span class="sourceLineNo">1865</span>        private int count = 1;<a name="line.1865"></a>
+<span class="sourceLineNo">1866</span><a name="line.1866"></a>
+<span class="sourceLineNo">1867</span>        @Override<a name="line.1867"></a>
+<span class="sourceLineNo">1868</span>        public Thread newThread(Runnable r) {<a name="line.1868"></a>
+<span class="sourceLineNo">1869</span>          return new Thread(r, threadNamePrefix + "-" + count++);<a name="line.1869"></a>
+<span class="sourceLineNo">1870</span>        }<a name="line.1870"></a>
+<span class="sourceLineNo">1871</span>      });<a name="line.1871"></a>
+<span class="sourceLineNo">1872</span>  }<a name="line.1872"></a>
+<span class="sourceLineNo">1873</span><a name="line.1873"></a>
+<span class="sourceLineNo">1874</span>   /**<a name="line.1874"></a>
+<span class="sourceLineNo">1875</span>    * @return True if its worth doing a flush before we put up the close flag.<a name="line.1875"></a>
+<span class="sourceLineNo">1876</span>    */<a name="line.1876"></a>
+<span class="sourceLineNo">1877</span>  private boolean worthPreFlushing() {<a name="line.1877"></a>
+<span class="sourceLineNo">1878</span>    return this.memStoreSizing.getDataSize() &gt;<a name="line.1878"></a>
+<span class="sourceLineNo">1879</span>      this.conf.getLong("hbase.hregion.preclose.flush.size", 1024 * 1024 * 5);<a name="line.1879"></a>
+<span class="sourceLineNo">1880</span>  }<a name="line.1880"></a>
+<span class="sourceLineNo">1881</span><a name="line.1881"></a>
+<span class="sourceLineNo">1882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1882"></a>
+<span class="sourceLineNo">1883</span>  // HRegion accessors<a name="line.1883"></a>
+<span class="sourceLineNo">1884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.1884"></a>
+<span class="sourceLineNo">1885</span><a name="line.1885"></a>
+<span class="sourceLineNo">1886</span>  @Override<a name="line.1886"></a>
+<span class="sourceLineNo">1887</span>  public TableDescriptor getTableDescriptor() {<a name="line.1887"></a>
+<span class="sourceLineNo">1888</span>    return this.htableDescriptor;<a name="line.1888"></a>
+<span class="sourceLineNo">1889</span>  }<a name="line.1889"></a>
+<span class="sourceLineNo">1890</span><a name="line.1890"></a>
+<span class="sourceLineNo">1891</span>  @VisibleForTesting<a name="line.1891"></a>
+<span class="sourceLineNo">1892</span>  void setTableDescriptor(TableDescriptor desc) {<a name="line.1892"></a>
+<span class="sourceLineNo">1893</span>    htableDescriptor = desc;<a name="line.1893"></a>
+<span class="sourceLineNo">1894</span>  }<a name="line.1894"></a>
+<span class="sourceLineNo">1895</span><a name="line.1895"></a>
+<span class="sourceLineNo">1896</span>  /** @return WAL in use for this region */<a name="line.1896"></a>
+<span class="sourceLineNo">1897</span>  public WAL getWAL() {<a name="line.1897"></a>
+<span class="sourceLineNo">1898</span>    return this.wal;<a name="line.1898"></a>
+<span class="sourceLineNo">1899</span>  }<a name="line.1899"></a>
+<span class="sourceLineNo">1900</span><a name="line.1900"></a>
+<span class="sourceLineNo">1901</span>  public BlockCache getBlockCache() {<a name="line.1901"></a>
+<span class="sourceLineNo">1902</span>    return this.blockCache;<a name="line.1902"></a>
+<span class="sourceLineNo">1903</span>  }<a name="line.1903"></a>
+<span class="sourceLineNo">1904</span><a name="line.1904"></a>
+<span class="sourceLineNo">1905</span>  /**<a name="line.1905"></a>
+<span class="sourceLineNo">1906</span>   * Only used for unit test which doesn't start region server.<a name="line.1906"></a>
+<span class="sourceLineNo">1907</span>   */<a name="line.1907"></a>
+<span class="sourceLineNo">1908</span>  @VisibleForTesting<a name="line.1908"></a>
+<span class="sourceLineNo">1909</span>  public void setBlockCache(BlockCache blockCache) {<a name="line.1909"></a>
+<span class="sourceLineNo">1910</span>    this.blockCache = blockCache;<a name="line.1910"></a>
+<span class="sourceLineNo">1911</span>  }<a name="line.1911"></a>
+<span class="sourceLineNo">1912</span><a name="line.1912"></a>
+<span class="sourceLineNo">1913</span>  public MobFileCache getMobFileCache() {<a name="line.1913"></a>
+<span class="sourceLineNo">1914</span>    return this.mobFileCache;<a name="line.1914"></a>
+<span class="sourceLineNo">1915</span>  }<a name="line.1915"></a>
+<span class="sourceLineNo">1916</span><a name="line.1916"></a>
+<span class="sourceLineNo">1917</span>  /**<a name="line.1917"></a>
+<span class="sourceLineNo">1918</span>   * Only used for unit test which doesn't start region server.<a name="line.1918"></a>
+<span class="sourceLineNo">1919</span>   */<a name="line.1919"></a>
+<span class="sourceLineNo">1920</span>  @VisibleForTesting<a name="line.1920"></a>
+<span class="sourceLineNo">1921</span>  public void setMobFileCache(MobFileCache mobFileCache) {<a name="line.1921"></a>
+<span class="sourceLineNo">1922</span>    this.mobFileCache = mobFileCache;<a name="line.1922"></a>
+<span class="sourceLineNo">1923</span>  }<a name="line.1923"></a>
+<span class="sourceLineNo">1924</span><a name="line.1924"></a>
+<span class="sourceLineNo">1925</span>  /**<a name="line.1925"></a>
+<span class="sourceLineNo">1926</span>   * @return split policy for this region.<a name="line.1926"></a>
+<span class="sourceLineNo">1927</span>   */<a name="line.1927"></a>
+<span class="sourceLineNo">1928</span>  public RegionSplitPolicy getSplitPolicy() {<a name="line.1928"></a>
+<span class="sourceLineNo">1929</span>    return this.splitPolicy;<a name="line.1929"></a>
+<span class="sourceLineNo">1930</span>  }<a name="line.1930"></a>
+<span class="sourceLineNo">1931</span><a name="line.1931"></a>
+<span class="sourceLineNo">1932</span>  /**<a name="line.1932"></a>
+<span class="sourceLineNo">1933</span>   * A split takes the config from the parent region &amp; passes it to the daughter<a name="line.1933"></a>
+<span class="sourceLineNo">1934</span>   * region's constructor. If 'conf' was passed, you would end up using the HTD<a name="line.1934"></a>
+<span class="sourceLineNo">1935</span>   * of the parent region in addition to the new daughter HTD. Pass 'baseConf'<a name="line.1935"></a>
+<span class="sourceLineNo">1936</span>   * to the daughter regions to avoid this tricky dedupe problem.<a name="line.1936"></a>
+<span class="sourceLineNo">1937</span>   * @return Configuration object<a name="line.1937"></a>
+<span class="sourceLineNo">1938</span>   */<a name="line.1938"></a>
+<span class="sourceLineNo">1939</span>  Configuration getBaseConf() {<a name="line.1939"></a>
+<span class="sourceLineNo">1940</span>    return this.baseConf;<a name="line.1940"></a>
+<span class="sourceLineNo">1941</span>  }<a name="line.1941"></a>
+<span class="sourceLineNo">1942</span><a name="line.1942"></a>
+<span class="sourceLineNo">1943</span>  /** @return {@link FileSystem} being used by this region */<a name="line.1943"></a>
+<span class="sourceLineNo">1944</span>  public FileSystem getFilesystem() {<a name="line.1944"></a>
+<span class="sourceLineNo">1945</span>    return fs.getFileSystem();<a name="line.1945"></a>
+<span class="sourceLineNo">1946</span>  }<a name="line.1946"></a>
+<span class="sourceLineNo">1947</span><a name="line.1947"></a>
+<span class="sourceLineNo">1948</span>  /** @return the {@link HRegionFileSystem} used by this region */<a name="line.1948"></a>
+<span class="sourceLineNo">1949</span>  public HRegionFileSystem getRegionFileSystem() {<a name="line.1949"></a>
+<span class="sourceLineNo">1950</span>    return this.fs;<a name="line.1950"></a>
+<span class="sourceLineNo">1951</span>  }<a name="line.1951"></a>
+<span class="sourceLineNo">1952</span><a name="line.1952"></a>
+<span class="sourceLineNo">1953</span>  /** @return the WAL {@link HRegionFileSystem} used by this region */<a name="line.1953"></a>
+<span class="sourceLineNo">1954</span>  HRegionFileSystem getRegionWALFileSystem() throws IOException {<a name="line.1954"></a>
+<span class="sourceLineNo">1955</span>    return new HRegionFileSystem(conf, getWalFileSystem(),<a name="line.1955"></a>
+<span class="sourceLineNo">1956</span>        FSUtils.getWALTableDir(conf, htableDescriptor.getTableName()), fs.getRegionInfo());<a name="line.1956"></a>
+<span class="sourceLineNo">1957</span>  }<a name="line.1957"></a>
+<span class="sourceLineNo">1958</span><a name="line.1958"></a>
+<span class="sourceLineNo">1959</span>  /** @return the WAL {@link FileSystem} being used by this region */<a name="line.1959"></a>
+<span class="sourceLineNo">1960</span>  FileSystem getWalFileSystem() throws IOException {<a name="line.1960"></a>
+<span class="sourceLineNo">1961</span>    if (walFS == null) {<a name="line.1961"></a>
+<span class="sourceLineNo">1962</span>      walFS = FSUtils.getWALFileSystem(conf);<a name="line.1962"></a>
+<span class="sourceLineNo">1963</span>    }<a name="line.1963"></a>
+<span class="sourceLineNo">1964</span>    return walFS;<a name="line.1964"></a>
+<span class="sourceLineNo">1965</span>  }<a name="line.1965"></a>
+<span class="sourceLineNo">1966</span><a name="line.1966"></a>
+<span class="sourceLineNo">1967</span>  /**<a name="line.1967"></a>
+<span class="sourceLineNo">1968</span>   * @return the Region directory under WALRootDirectory<a name="line.1968"></a>
+<span class="sourceLineNo">1969</span>   * @throws IOException if there is an error getting WALRootDir<a name="line.1969"></a>
+<span class="sourceLineNo">1970</span>   */<a name="line.1970"></a>
+<span class="sourceLineNo">1971</span>  @VisibleForTesting<a name="line.1971"></a>
+<span class="sourceLineNo">1972</span>  public Path getWALRegionDir() throws IOException {<a name="line.1972"></a>
+<span class="sourceLineNo">1973</span>    if (regionDir == null) {<a name="line.1973"></a>
+<span class="sourceLineNo">1974</span>      regionDir = FSUtils.getWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.1974"></a>
+<span class="sourceLineNo">1975</span>          getRegionInfo().getEncodedName());<a name="line.1975"></a>
+<span class="sourceLineNo">1976</span>    }<a name="line.1976"></a>
+<span class="sourceLineNo">1977</span>    return regionDir;<a name="line.1977"></a>
+<span class="sourceLineNo">1978</span>  }<a name="line.1978"></a>
+<span class="sourceLineNo">1979</span><a name="line.1979"></a>
+<span class="sourceLineNo">1980</span>  @Override<a name="line.1980"></a>
+<span class="sourceLineNo">1981</span>  public long getEarliestFlushTimeForAllStores() {<a name="line.1981"></a>
+<span class="sourceLineNo">1982</span>    return Collections.min(lastStoreFlushTimeMap.values());<a name="line.1982"></a>
+<span class="sourceLineNo">1983</span>  }<a name="line.1983"></a>
+<span class="sourceLineNo">1984</span><a name="line.1984"></a>
+<span class="sourceLineNo">1985</span>  @Override<a name="line.1985"></a>
+<span class="sourceLineNo">1986</span>  public long getOldestHfileTs(boolean majorCompactionOnly) throws IOException {<a name="line.1986"></a>
+<span class="sourceLineNo">1987</span>    long result = Long.MAX_VALUE;<a name="line.1987"></a>
+<span class="sourceLineNo">1988</span>    for (HStore store : stores.values()) {<a name="line.1988"></a>
+<span class="sourceLineNo">1989</span>      Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.1989"></a>
+<span class="sourceLineNo">1990</span>      if (storeFiles == null) {<a name="line.1990"></a>
+<span class="sourceLineNo">1991</span>        continue;<a name="line.1991"></a>
+<span class="sourceLineNo">1992</span>      }<a name="line.1992"></a>
+<span class="sourceLineNo">1993</span>      for (HStoreFile file : storeFiles) {<a name="line.1993"></a>
+<span class="sourceLineNo">1994</span>        StoreFileReader sfReader = file.getReader();<a name="line.1994"></a>
+<span class="sourceLineNo">1995</span>        if (sfReader == null) {<a name="line.1995"></a>
+<span class="sourceLineNo">1996</span>          continue;<a name="line.1996"></a>
+<span class="sourceLineNo">1997</span>        }<a name="line.1997"></a>
+<span class="sourceLineNo">1998</span>        HFile.Reader reader = sfReader.getHFileReader();<a name="line.1998"></a>
+<span class="sourceLineNo">1999</span>        if (reader == null) {<a name="line.1999"></a>
+<span class="sourceLineNo">2000</span>          continue;<a name="line.2000"></a>
+<span class="sourceLineNo">2001</span>        }<a name="line.2001"></a>
+<span class="sourceLineNo">2002</span>        if (majorCompactionOnly) {<a name="line.2002"></a>
+<span class="sourceLineNo">2003</span>          byte[] val = reader.loadFileInfo().get(MAJOR_COMPACTION_KEY);<a name="line.2003"></a>
+<span class="sourceLineNo">2004</span>          if (val == null || !Bytes.toBoolean(val)) {<a name="line.2004"></a>
+<span class="sourceLineNo">2005</span>            continue;<a name="line.2005"></a>
+<span class="sourceLineNo">2006</span>          }<a name="line.2006"></a>
+<span class="sourceLineNo">2007</span>        }<a name="line.2007"></a>
+<span class="sourceLineNo">2008</span>        result = Math.min(result, reader.getFileContext().getFileCreateTime());<a name="line.2008"></a>
+<span class="sourceLineNo">2009</span>      }<a name="line.2009"></a>
+<span class="sourceLineNo">2010</span>    }<a name="line.2010"></a>
+<span class="sourceLineNo">2011</span>    return result == Long.MAX_VALUE ? 0 : result;<a name="line.2011"></a>
+<span class="sourceLineNo">2012</span>  }<a name="line.2012"></a>
+<span class="sourceLineNo">2013</span><a name="line.2013"></a>
+<span class="sourceLineNo">2014</span>  RegionLoad.Builder setCompleteSequenceId(RegionLoad.Builder regionLoadBldr) {<a name="line.2014"></a>
+<span class="sourceLineNo">2015</span>    long lastFlushOpSeqIdLocal = this.lastFlushOpSeqId;<a name="line.2015"></a>
+<span class="sourceLineNo">2016</span>    byte[] encodedRegionName = this.getRegionInfo().getEncodedNameAsBytes();<a name="line.2016"></a>
+<span class="sourceLineNo">2017</span>    regionLoadBldr.clearStoreCompleteSequenceId();<a name="line.2017"></a>
+<span class="sourceLineNo">2018</span>    for (byte[] familyName : this.stores.keySet()) {<a name="line.2018"></a>
+<span class="sourceLineNo">2019</span>      long earliest = this.wal.getEarliestMemStoreSeqNum(encodedRegionName, familyName);<a name="line.2019"></a>
+<span class="sourceLineNo">2020</span>      // Subtract - 1 to go earlier than the current oldest, unflushed edit in memstore; this will<a name="line.2020"></a>
+<span class="sourceLineNo">2021</span>      // give us a sequence id that is for sure flushed. We want edit replay to start after this<a name="line.2021"></a>
+<span class="sourceLineNo">2022</span>      // sequence id in this region. If NO_SEQNUM, use the regions maximum flush id.<a name="line.2022"></a>
+<span class="sourceLineNo">2023</span>      long csid = (earliest == HConstants.NO_SEQNUM)? lastFlushOpSeqIdLocal: earliest - 1;<a name="line.2023"></a>
+<span class="sourceLineNo">2024</span>      regionLoadBldr.addStoreCompleteSequenceId(StoreSequenceId.newBuilder()<a name="line.2024"></a>
+<span class="sourceLineNo">2025</span>          .setFamilyName(UnsafeByteOperations.unsafeWrap(familyName)).setSequenceId(csid).build());<a name="line.2025"></a>
+<span class="sourceLineNo">2026</span>    }<a name="line.2026"></a>
+<span class="sourceLineNo">2027</span>    return regionLoadBldr.setCompleteSequenceId(getMaxFlushedSeqId());<a name="line.2027"></a>
+<span class="sourceLineNo">2028</span>  }<a name="line.2028"></a>
+<span class="sourceLineNo">2029</span><a name="line.2029"></a>
+<span class="sourceLineNo">2030</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2030"></a>
+<span class="sourceLineNo">2031</span>  // HRegion maintenance.<a name="line.2031"></a>
+<span class="sourceLineNo">2032</span>  //<a name="line.2032"></a>
+<span class="sourceLineNo">2033</span>  // These methods are meant to be called periodically by the HRegionServer for<a name="line.2033"></a>
+<span class="sourceLineNo">2034</span>  // upkeep.<a name="line.2034"></a>
+<span class="sourceLineNo">2035</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2035"></a>
+<span class="sourceLineNo">2036</span>  /**<a name="line.2036"></a>
+<span class="sourceLineNo">2037</span>   * Do preparation for pending compaction.<a name="line.2037"></a>
+<span class="sourceLineNo">2038</span>   * @throws IOException<a name="line.2038"></a>
+<span class="sourceLineNo">2039</span>   */<a name="line.2039"></a>
+<span class="sourceLineNo">2040</span>  protected void doRegionCompactionPrep() throws IOException {<a name="line.2040"></a>
+<span class="sourceLineNo">2041</span>  }<a name="line.2041"></a>
+<span class="sourceLineNo">2042</span><a name="line.2042"></a>
+<span class="sourceLineNo">2043</span>  /**<a name="line.2043"></a>
+<span class="sourceLineNo">2044</span>   * Synchronously compact all stores in the region.<a name="line.2044"></a>
+<span class="sourceLineNo">2045</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2045"></a>
+<span class="sourceLineNo">2046</span>   * time-sensitive thread.<a name="line.2046"></a>
+<span class="sourceLineNo">2047</span>   * &lt;p&gt;Note that no locks are taken to prevent possible conflicts between<a name="line.2047"></a>
+<span class="sourceLineNo">2048</span>   * compaction and splitting activities. The regionserver does not normally compact<a name="line.2048"></a>
+<span class="sourceLineNo">2049</span>   * and split in parallel. However by calling this method you may introduce<a name="line.2049"></a>
+<span class="sourceLineNo">2050</span>   * unexpected and unhandled concurrency. Don't do this unless you know what<a name="line.2050"></a>
+<span class="sourceLineNo">2051</span>   * you are doing.<a name="line.2051"></a>
+<span class="sourceLineNo">2052</span>   *<a name="line.2052"></a>
+<span class="sourceLineNo">2053</span>   * @param majorCompaction True to force a major compaction regardless of thresholds<a name="line.2053"></a>
+<span class="sourceLineNo">2054</span>   * @throws IOException<a name="line.2054"></a>
+<span class="sourceLineNo">2055</span>   */<a name="line.2055"></a>
+<span class="sourceLineNo">2056</span>  public void compact(boolean majorCompaction) throws IOException {<a name="line.2056"></a>
+<span class="sourceLineNo">2057</span>    if (majorCompaction) {<a name="line.2057"></a>
+<span class="sourceLineNo">2058</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.2058"></a>
+<span class="sourceLineNo">2059</span>    }<a name="line.2059"></a>
+<span class="sourceLineNo">2060</span>    for (HStore s : stores.values()) {<a name="line.2060"></a>
+<span class="sourceLineNo">2061</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2061"></a>
+<span class="sourceLineNo">2062</span>      if (compaction.isPresent()) {<a name="line.2062"></a>
+<span class="sourceLineNo">2063</span>        ThroughputController controller = null;<a name="line.2063"></a>
+<span class="sourceLineNo">2064</span>        if (rsServices != null) {<a name="line.2064"></a>
+<span class="sourceLineNo">2065</span>          controller = CompactionThroughputControllerFactory.create(rsServices, conf);<a name="line.2065"></a>
 <span class="sourceLineNo">2066</span>        }<a name="line.2066"></a>
-<span class="sourceLineNo">2067</span>        compact(compaction.get(), s, controller, null);<a name="line.2067"></a>
-<span class="sourceLineNo">2068</span>      }<a name="line.2068"></a>
-<span class="sourceLineNo">2069</span>    }<a name="line.2069"></a>
-<span class="sourceLineNo">2070</span>  }<a name="line.2070"></a>
-<span class="sourceLineNo">2071</span><a name="line.2071"></a>
-<span class="sourceLineNo">2072</span>  /**<a name="line.2072"></a>
-<span class="sourceLineNo">2073</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2073"></a>
-<span class="sourceLineNo">2074</span>   * &lt;p&gt;<a name="line.2074"></a>
-<span class="sourceLineNo">2075</span>   * It is used by utilities and testing<a name="line.2075"></a>
-<span class="sourceLineNo">2076</span>   */<a name="line.2076"></a>
-<span class="sourceLineNo">2077</span>  @VisibleForTesting<a name="line.2077"></a>
-<span class="sourceLineNo">2078</span>  public void compactStores() throws IOException {<a name="line.2078"></a>
-<span class="sourceLineNo">2079</span>    for (HStore s : stores.values()) {<a name="line.2079"></a>
-<span class="sourceLineNo">2080</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2080"></a>
-<span class="sourceLineNo">2081</span>      if (compaction.isPresent()) {<a name="line.2081"></a>
-<span class="sourceLineNo">2082</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2082"></a>
-<span class="sourceLineNo">2083</span>      }<a name="line.2083"></a>
-<span class="sourceLineNo">2084</span>    }<a name="line.2084"></a>
-<span class="sourceLineNo">2085</span>  }<a name="line.2085"></a>
-<span class="sourceLineNo">2086</span><a name="line.2086"></a>
-<span class="sourceLineNo">2087</span>  /**<a name="line.2087"></a>
-<span class="sourceLineNo">2088</span>   * This is a helper function that compact the given store.<a name="line.2088"></a>
-<span class="sourceLineNo">2089</span>   * &lt;p&gt;<a name="line.2089"></a>
-<span class="sourceLineNo">2090</span>   * It is used by utilities and testing<a name="line.2090"></a>
-<span class="sourceLineNo">2091</span>   */<a name="line.2091"></a>
-<span class="sourceLineNo">2092</span>  @VisibleForTesting<a name="line.2092"></a>
-<span class="sourceLineNo">2093</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2093"></a>
-<span class="sourceLineNo">2094</span>    HStore s = getStore(family);<a name="line.2094"></a>
-<span class="sourceLineNo">2095</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2095"></a>
-<span class="sourceLineNo">2096</span>    if (compaction.isPresent()) {<a name="line.2096"></a>
-<span class="sourceLineNo">2097</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2097"></a>
-<span class="sourceLineNo">2098</span>    }<a name="line.2098"></a>
-<span class="sourceLineNo">2099</span>  }<a name="line.2099"></a>
-<span class="sourceLineNo">2100</span><a name="line.2100"></a>
-<span class="sourceLineNo">2101</span>  /**<a name="line.2101"></a>
-<span class="sourceLineNo">2102</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2102"></a>
-<span class="sourceLineNo">2103</span>   * HStores if necessary.<a name="line.2103"></a>
-<span class="sourceLineNo">2104</span>   *<a name="line.2104"></a>
-<span class="sourceLineNo">2105</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2105"></a>
-<span class="sourceLineNo">2106</span>   * time-sensitive thread.<a name="line.2106"></a>
+<span class="sourceLineNo">2067</span>        if (controller == null) {<a name="line.2067"></a>
+<span class="sourceLineNo">2068</span>          controller = NoLimitThroughputController.INSTANCE;<a name="line.2068"></a>
+<span class="sourceLineNo">2069</span>        }<a name="line.2069"></a>
+<span class="sourceLineNo">2070</span>        compact(compaction.get(), s, controller, null);<a name="line.2070"></a>
+<span class="sourceLineNo">2071</span>      }<a name="line.2071"></a>
+<span class="sourceLineNo">2072</span>    }<a name="line.2072"></a>
+<span class="sourceLineNo">2073</span>  }<a name="line.2073"></a>
+<span class="sourceLineNo">2074</span><a name="line.2074"></a>
+<span class="sourceLineNo">2075</span>  /**<a name="line.2075"></a>
+<span class="sourceLineNo">2076</span>   * This is a helper function that compact all the stores synchronously.<a name="line.2076"></a>
+<span class="sourceLineNo">2077</span>   * &lt;p&gt;<a name="line.2077"></a>
+<span class="sourceLineNo">2078</span>   * It is used by utilities and testing<a name="line.2078"></a>
+<span class="sourceLineNo">2079</span>   */<a name="line.2079"></a>
+<span class="sourceLineNo">2080</span>  @VisibleForTesting<a name="line.2080"></a>
+<span class="sourceLineNo">2081</span>  public void compactStores() throws IOException {<a name="line.2081"></a>
+<span class="sourceLineNo">2082</span>    for (HStore s : stores.values()) {<a name="line.2082"></a>
+<span class="sourceLineNo">2083</span>      Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2083"></a>
+<span class="sourceLineNo">2084</span>      if (compaction.isPresent()) {<a name="line.2084"></a>
+<span class="sourceLineNo">2085</span>        compact(compaction.get(), s, NoLimitThroughputController.INSTANCE, null);<a name="line.2085"></a>
+<span class="sourceLineNo">2086</span>      }<a name="line.2086"></a>
+<span class="sourceLineNo">2087</span>    }<a name="line.2087"></a>
+<span class="sourceLineNo">2088</span>  }<a name="line.2088"></a>
+<span class="sourceLineNo">2089</span><a name="line.2089"></a>
+<span class="sourceLineNo">2090</span>  /**<a name="line.2090"></a>
+<span class="sourceLineNo">2091</span>   * This is a helper function that compact the given store.<a name="line.2091"></a>
+<span class="sourceLineNo">2092</span>   * &lt;p&gt;<a name="line.2092"></a>
+<span class="sourceLineNo">2093</span>   * It is used by utilities and testing<a name="line.2093"></a>
+<span class="sourceLineNo">2094</span>   */<a name="line.2094"></a>
+<span class="sourceLineNo">2095</span>  @VisibleForTesting<a name="line.2095"></a>
+<span class="sourceLineNo">2096</span>  void compactStore(byte[] family, ThroughputController throughputController) throws IOException {<a name="line.2096"></a>
+<span class="sourceLineNo">2097</span>    HStore s = getStore(family);<a name="line.2097"></a>
+<span class="sourceLineNo">2098</span>    Optional&lt;CompactionContext&gt; compaction = s.requestCompaction();<a name="line.2098"></a>
+<span class="sourceLineNo">2099</span>    if (compaction.isPresent()) {<a name="line.2099"></a>
+<span class="sourceLineNo">2100</span>      compact(compaction.get(), s, throughputController, null);<a name="line.2100"></a>
+<span class="sourceLineNo">2101</span>    }<a name="line.2101"></a>
+<span class="sourceLineNo">2102</span>  }<a name="line.2102"></a>
+<span class="sourceLineNo">2103</span><a name="line.2103"></a>
+<span class="sourceLineNo">2104</span>  /**<a name="line.2104"></a>
+<span class="sourceLineNo">2105</span>   * Called by compaction thread and after region is opened to compact the<a name="line.2105"></a>
+<span class="sourceLineNo">2106</span>   * HStores if necessary.<a name="line.2106"></a>
 <span class="sourceLineNo">2107</span>   *<a name="line.2107"></a>
-<span class="sourceLineNo">2108</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2108"></a>
-<span class="sourceLineNo">2109</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2109"></a>
-<span class="sourceLineNo">2110</span>   * server does them sequentially and not in parallel.<a name="line.2110"></a>
-<span class="sourceLineNo">2111</span>   *<a name="line.2111"></a>
-<span class="sourceLineNo">2112</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2112"></a>
-<span class="sourceLineNo">2113</span>   * @param throughputController<a name="line.2113"></a>
-<span class="sourceLineNo">2114</span>   * @return whether the compaction completed<a name="line.2114"></a>
-<span class="sourceLineNo">2115</span>   */<a name="line.2115"></a>
-<span class="sourceLineNo">2116</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2116"></a>
-<span class="sourceLineNo">2117</span>      ThroughputController throughputController) throws IOException {<a name="line.2117"></a>
-<span class="sourceLineNo">2118</span>    return compact(compaction, store, throughputController, null);<a name="line.2118"></a>
-<span class="sourceLineNo">2119</span>  }<a name="line.2119"></a>
-<span class="sourceLineNo">2120</span><a name="line.2120"></a>
-<span class="sourceLineNo">2121</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2121"></a>
-<span class="sourceLineNo">2122</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2122"></a>
-<span class="sourceLineNo">2123</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2123"></a>
-<span class="sourceLineNo">2124</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2124"></a>
-<span class="sourceLineNo">2125</span>    }<a name="line.2125"></a>
-<span class="sourceLineNo">2126</span>    return false;<a name="line.2126"></a>
-<span class="sourceLineNo">2127</span>  }<a name="line.2127"></a>
-<span class="sourceLineNo">2128</span><a name="line.2128"></a>
-<span class="sourceLineNo">2129</span>  /**<a name="line.2129"></a>
-<span class="sourceLineNo">2130</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2130"></a>
-<span class="sourceLineNo">2131</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2131"></a>
-<span class="sourceLineNo">2132</span>   * region split, region close and region bulk load).<a name="line.2132"></a>
-<span class="sourceLineNo">2133</span>   *<a name="line.2133"></a>
-<span class="sourceLineNo">2134</span>   *  user scan ---&gt; region read lock<a name="line.2134"></a>
-<span class="sourceLineNo">2135</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2135"></a>
-<span class="sourceLineNo">2136</span>   *  region close --&gt; region write lock<a name="line.2136"></a>
-<span class="sourceLineNo">2137</span>   *  region bulk load --&gt; region write lock<a name="line.2137"></a>
-<span class="sourceLineNo">2138</span>   *<a name="line.2138"></a>
-<span class="sourceLineNo">2139</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2139"></a>
-<span class="sourceLineNo">2140</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2140"></a>
-<span class="sourceLineNo">2141</span>   * will help the store file accounting).<a name="line.2141"></a>
-<span class="sourceLineNo">2142</span>   * They can run almost concurrently at the region level.<a name="line.2142"></a>
-<span class="sourceLineNo">2143</span>   *<a name="line.2143"></a>
-<span class="sourceLineNo">2144</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2144"></a>
-<span class="sourceLineNo">2145</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2145"></a>
-<span class="sourceLineNo">2146</span>   * not acquire region read lock.<a name="line.2146"></a>
-<span class="sourceLineNo">2147</span>   *<a name="line.2147"></a>
-<span class="sourceLineNo">2148</span>   * Here are the steps for compaction:<a name="line.2148"></a>
-<span class="sourceLineNo">2149</span>   * 1. obtain list of StoreFile's<a name="line.2149"></a>
-<span class="sourceLineNo">2150</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2150"></a>
-<span class="sourceLineNo">2151</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2151"></a>
-<span class="sourceLineNo">2152</span>   * 4. swap in compacted files<a name="line.2152"></a>
-<span class="sourceLineNo">2153</span>   *<a name="line.2153"></a>
-<span class="sourceLineNo">2154</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2154"></a>
-<span class="sourceLineNo">2155</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2155"></a>
-<span class="sourceLineNo">2156</span>   * compactor and stripe compactor).<a name="line.2156"></a>
-<span class="sourceLineNo">2157</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2157"></a>
-<span class="sourceLineNo">2158</span>   * user scanners.<a name="line.2158"></a>
-<span class="sourceLineNo">2159</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2159"></a>
-<span class="sourceLineNo">2160</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2160"></a>
-<span class="sourceLineNo">2161</span>   * since they are not needed anymore.<a name="line.2161"></a>
-<span class="sourceLineNo">2162</span>   * This will not conflict with compaction.<a name="line.2162"></a>
-<span class="sourceLineNo">2163</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2163"></a>
-<span class="sourceLineNo">2164</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2164"></a>
-<span class="sourceLineNo">2165</span>   *   (for multi-family atomicy).<a name="line.2165"></a>
-<span class="sourceLineNo">2166</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2166"></a>
-<span class="sourceLineNo">2167</span>   * In HRegion#doClose(), we have :<a name="line.2167"></a>
-<span class="sourceLineNo">2168</span>   * synchronized (writestate) {<a name="line.2168"></a>
-<span class="sourceLineNo">2169</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2169"></a>
-<span class="sourceLineNo">2170</span>   *   // region.<a name="line.2170"></a>
-<span class="sourceLineNo">2171</span>   *   canFlush = !writestate.readOnly;<a name="line.2171"></a>
-<span class="sourceLineNo">2172</span>   *   writestate.writesEnabled = false;<a name="line.2172"></a>
-<span class="sourceLineNo">2173</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2173"></a>
-<span class="sourceLineNo">2174</span>   *   waitForFlushesAndCompactions();<a name="line.2174"></a>
-<span class="sourceLineNo">2175</span>   * }<a name="line.2175"></a>
-<span class="sourceLineNo">2176</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2176"></a>
-<span class="sourceLineNo">2177</span>   * and in HRegion.compact()<a name="line.2177"></a>
-<span class="sourceLineNo">2178</span>   *  try {<a name="line.2178"></a>
-<span class="sourceLineNo">2179</span>   *    synchronized (writestate) {<a name="line.2179"></a>
-<span class="sourceLineNo">2180</span>   *    if (writestate.writesEnabled) {<a name="line.2180"></a>
-<span class="sourceLineNo">2181</span>   *      wasStateSet = true;<a name="line.2181"></a>
-<span class="sourceLineNo">2182</span>   *      ++writestate.compacting;<a name="line.2182"></a>
-<span class="sourceLineNo">2183</span>   *    } else {<a name="line.2183"></a>
-<span class="sourceLineNo">2184</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2184"></a>
-<span class="sourceLineNo">2185</span>   *      LOG.info(msg);<a name="line.2185"></a>
-<span class="sourceLineNo">2186</span>   *      status.abort(msg);<a name="line.2186"></a>
-<span class="sourceLineNo">2187</span>   *      return false;<a name="line.2187"></a>
-<span class="sourceLineNo">2188</span>   *    }<a name="line.2188"></a>
-<span class="sourceLineNo">2189</span>   *  }<a name="line.2189"></a>
-<span class="sourceLineNo">2190</span>   * Also in compactor.performCompaction():<a name="line.2190"></a>
-<span class="sourceLineNo">2191</span>   * check periodically to see if a system stop is requested<a name="line.2191"></a>
-<span class="sourceLineNo">2192</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2192"></a>
-<span class="sourceLineNo">2193</span>   *   bytesWritten += len;<a name="line.2193"></a>
-<span class="sourceLineNo">2194</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2194"></a>
-<span class="sourceLineNo">2195</span>   *     bytesWritten = 0;<a name="line.2195"></a>
-<span class="sourceLineNo">2196</span>   *     if (!store.areWritesEnabled()) {<a name="line.2196"></a>
-<span class="sourceLineNo">2197</span>   *       progress.cancel();<a name="line.2197"></a>
-<span class="sourceLineNo">2198</span>   *       return false;<a name="line.2198"></a>
-<span class="sourceLineNo">2199</span>   *     }<a name="line.2199"></a>
-<span class="sourceLineNo">2200</span>   *   }<a name="line.2200"></a>
-<span class="sourceLineNo">2201</span>   * }<a name="line.2201"></a>
-<span class="sourceLineNo">2202</span>   */<a name="line.2202"></a>
-<span class="sourceLineNo">2203</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2203"></a>
-<span class="sourceLineNo">2204</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2204"></a>
-<span class="sourceLineNo">2205</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2205"></a>
-<span class="sourceLineNo">2206</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2206"></a>
-<span class="sourceLineNo">2207</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2207"></a>
-<span class="sourceLineNo">2208</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2208"></a>
-<span class="sourceLineNo">2209</span>      store.cancelRequestedCompaction(compaction);<a name="line.2209"></a>
-<span class="sourceLineNo">2210</span>      return false;<a name="line.2210"></a>
-<span class="sourceLineNo">2211</span>    }<a name="line.2211"></a>
-<span class="sourceLineNo">2212</span><a name="line.2212"></a>
-<span class="sourceLineNo">2213</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2213"></a>
-<span class="sourceLineNo">2214</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2214"></a>
-<span class="sourceLineNo">2215</span>          + " because this cluster is transiting sync replication state"<a name="line.2215"></a>
-<span class="sourceLineNo">2216</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2216"></a>
-<span class="sourceLineNo">2217</span>      store.cancelRequestedCompaction(compaction);<a name="line.2217"></a>
-<span class="sourceLineNo">2218</span>      return false;<a name="line.2218"></a>
-<span class="sourceLineNo">2219</span>    }<a name="line.2219"></a>
-<span class="sourceLineNo">2220</span><a name="line.2220"></a>
-<span class="sourceLineNo">2221</span>    MonitoredTask status = null;<a name="line.2221"></a>
-<span class="sourceLineNo">2222</span>    boolean requestNeedsCancellation = true;<a name="line.2222"></a>
-<span class="sourceLineNo">2223</span>    try {<a name="line.2223"></a>
-<span class="sourceLineNo">2224</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2224"></a>
-<span class="sourceLineNo">2225</span>      if (stores.get(cf) != store) {<a name="line.2225"></a>
-<span class="sourceLineNo">2226</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2226"></a>
-<span class="sourceLineNo">2227</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2227"></a>
-<span class="sourceLineNo">2228</span>            + " It may be caused by the roll back of split transaction");<a name="line.2228"></a>
-<span class="sourceLineNo">2229</span>        return false;<a name="line.2229"></a>
-<span class="sourceLineNo">2230</span>      }<a name="line.2230"></a>
-<span class="sourceLineNo">2231</span><a name="line.2231"></a>
-<span class="sourceLineNo">2232</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2232"></a>
-<span class="sourceLineNo">2233</span>      status.enableStatusJournal(false);<a name="line.2233"></a>
-<span class="sourceLineNo">2234</span>      if (this.closed.get()) {<a name="line.2234"></a>
-<span class="sourceLineNo">2235</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2235"></a>
-<span class="sourceLineNo">2236</span>        LOG.debug(msg);<a name="line.2236"></a>
-<span class="sourceLineNo">2237</span>        status.abort(msg);<a name="line.2237"></a>
-<span class="sourceLineNo">2238</span>        return false;<a name="line.2238"></a>
-<span class="sourceLineNo">2239</span>      }<a name="line.2239"></a>
-<span class="sourceLineNo">2240</span>      boolean wasStateSet = false;<a name="line.2240"></a>
-<span class="sourceLineNo">2241</span>      try {<a name="line.2241"></a>
-<span class="sourceLineNo">2242</span>        synchronized (writestate) {<a name="line.2242"></a>
-<span class="sourceLineNo">2243</span>          if (writestate.writesEnabled) {<a name="line.2243"></a>
-<span class="sourceLineNo">2244</span>            wasStateSet = true;<a name="line.2244"></a>
-<span class="sourceLineNo">2245</span>            writestate.compacting.incrementAndGet();<a name="line.2245"></a>
-<span class="sourceLineNo">2246</span>          } else {<a name="line.2246"></a>
-<span class="sourceLineNo">2247</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2247"></a>
-<span class="sourceLineNo">2248</span>            LOG.info(msg);<a name="line.2248"></a>
-<span class="sourceLineNo">2249</span>            status.abort(msg);<a name="line.2249"></a>
-<span class="sourceLineNo">2250</span>            return false;<a name="line.2250"></a>
-<span class="sourceLineNo">2251</span>          }<a name="line.2251"></a>
-<span class="sourceLineNo">2252</span>        }<a name="line.2252"></a>
-<span class="sourceLineNo">2253</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2253"></a>
-<span class="sourceLineNo">2254</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2254"></a>
-<span class="sourceLineNo">2255</span>        doRegionCompactionPrep();<a name="line.2255"></a>
-<span class="sourceLineNo">2256</span>        try {<a name="line.2256"></a>
-<span class="sourceLineNo">2257</span>          status.setStatus("Compacting store " + store);<a name="line.2257"></a>
-<span class="sourceLineNo">2258</span>          // We no longer need to cancel the request on the way out of this<a name="line.2258"></a>
-<span class="sourceLineNo">2259</span>          // method because Store#compact will clean up unconditionally<a name="line.2259"></a>
-<span class="sourceLineNo">2260</span>          requestNeedsCancellation = false;<a name="line.2260"></a>
-<span class="sourceLineNo">2261</span>          store.compact(compaction, throughputController, user);<a name="line.2261"></a>
-<span class="sourceLineNo">2262</span>        } catch (InterruptedIOException iioe) {<a name="line.2262"></a>
-<span class="sourceLineNo">2263</span>          String msg = "compaction interrupted";<a name="line.2263"></a>
-<span class="sourceLineNo">2264</span>          LOG.info(msg, iioe);<a name="line.2264"></a>
-<span class="sourceLineNo">2265</span>          status.abort(msg);<a name="line.2265"></a>
-<span class="sourceLineNo">2266</span>          return false;<a name="line.2266"></a>
-<span class="sourceLineNo">2267</span>        }<a name="line.2267"></a>
-<span class="sourceLineNo">2268</span>      } finally {<a name="line.2268"></a>
-<span class="sourceLineNo">2269</span>        if (wasStateSet) {<a name="line.2269"></a>
-<span class="sourceLineNo">2270</span>          synchronized (writestate) {<a name="line.2270"></a>
-<span class="sourceLineNo">2271</span>            writestate.compacting.decrementAndGet();<a name="line.2271"></a>
-<span class="sourceLineNo">2272</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2272"></a>
-<span class="sourceLineNo">2273</span>              writestate.notifyAll();<a name="line.2273"></a>
-<span class="sourceLineNo">2274</span>            }<a name="line.2274"></a>
-<span class="sourceLineNo">2275</span>          }<a name="line.2275"></a>
-<span class="sourceLineNo">2276</span>        }<a name="line.2276"></a>
-<span class="sourceLineNo">2277</span>      }<a name="line.2277"></a>
-<span class="sourceLineNo">2278</span>      status.markComplete("Compaction complete");<a name="line.2278"></a>
-<span class="sourceLineNo">2279</span>      return true;<a name="line.2279"></a>
-<span class="sourceLineNo">2280</span>    } finally {<a name="line.2280"></a>
-<span class="sourceLineNo">2281</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2281"></a>
-<span class="sourceLineNo">2282</span>      if (status != null) {<a name="line.2282"></a>
-<span class="sourceLineNo">2283</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2283"></a>
-<span class="sourceLineNo">2284</span>        status.cleanup();<a name="line.2284"></a>
-<span class="sourceLineNo">2285</span>      }<a name="line.2285"></a>
-<span class="sourceLineNo">2286</span>    }<a name="line.2286"></a>
-<span class="sourceLineNo">2287</span>  }<a name="line.2287"></a>
-<span class="sourceLineNo">2288</span><a name="line.2288"></a>
-<span class="sourceLineNo">2289</span>  /**<a name="line.2289"></a>
-<span class="sourceLineNo">2290</span>   * Flush the cache.<a name="line.2290"></a>
-<span class="sourceLineNo">2291</span>   *<a name="line.2291"></a>
-<span class="sourceLineNo">2292</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2292"></a>
-<span class="sourceLineNo">2293</span>   * &lt;ol&gt;<a name="line.2293"></a>
-<span class="sourceLineNo">2294</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2294"></a>
-<span class="sourceLineNo">2295</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2295"></a>
-<span class="sourceLineNo">2296</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2296"></a>
-<span class="sourceLineNo">2297</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2297"></a>
-<span class="sourceLineNo">2298</span>   * &lt;/ol&gt;<a name="line.2298"></a>
-<span class="sourceLineNo">2299</span>   *<a name="line.2299"></a>
-<span class="sourceLineNo">2300</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2300"></a>
-<span class="sourceLineNo">2301</span>   * time-sensitive thread.<a name="line.2301"></a>
-<span class="sourceLineNo">2302</span>   * @param force whether we want to force a flush of all stores<a name="line.2302"></a>
-<span class="sourceLineNo">2303</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2303"></a>
-<span class="sourceLineNo">2304</span>   * the region needs compacting<a name="line.2304"></a>
-<span class="sourceLineNo">2305</span>   *<a name="line.2305"></a>
-<span class="sourceLineNo">2306</span>   * @throws IOException general io exceptions<a name="line.2306"></a>
-<span class="sourceLineNo">2307</span>   * because a snapshot was not properly persisted.<a name="line.2307"></a>
-<span class="sourceLineNo">2308</span>   */<a name="line.2308"></a>
-<span class="sourceLineNo">2309</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2309"></a>
-<span class="sourceLineNo">2310</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2310"></a>
-<span class="sourceLineNo">2311</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2311"></a>
-<span class="sourceLineNo">2312</span>  }<a name="line.2312"></a>
-<span class="sourceLineNo">2313</span><a name="line.2313"></a>
-<span class="sourceLineNo">2314</span>  public interface FlushResult {<a name="line.2314"></a>
-<span class="sourceLineNo">2315</span>    enum Result {<a name="line.2315"></a>
-<span class="sourceLineNo">2316</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2316"></a>
-<span class="sourceLineNo">2317</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2317"></a>
-<span class="sourceLineNo">2318</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2318"></a>
-<span class="sourceLineNo">2319</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2319"></a>
-<span class="sourceLineNo">2320</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2320"></a>
-<span class="sourceLineNo">2321</span>      CANNOT_FLUSH<a name="line.2321"></a>
-<span class="sourceLineNo">2322</span>    }<a name="line.2322"></a>
-<span class="sourceLineNo">2323</span><a name="line.2323"></a>
-<span class="sourceLineNo">2324</span>    /** @return the detailed result code */<a name="line.2324"></a>
-<span class="sourceLineNo">2325</span>    Result getResult();<a name="line.2325"></a>
+<span class="sourceLineNo">2108</span>   * &lt;p&gt;This operation could block for a long time, so don't call it from a<a name="line.2108"></a>
+<span class="sourceLineNo">2109</span>   * time-sensitive thread.<a name="line.2109"></a>
+<span class="sourceLineNo">2110</span>   *<a name="line.2110"></a>
+<span class="sourceLineNo">2111</span>   * Note that no locking is necessary at this level because compaction only<a name="line.2111"></a>
+<span class="sourceLineNo">2112</span>   * conflicts with a region split, and that cannot happen because the region<a name="line.2112"></a>
+<span class="sourceLineNo">2113</span>   * server does them sequentially and not in parallel.<a name="line.2113"></a>
+<span class="sourceLineNo">2114</span>   *<a name="line.2114"></a>
+<span class="sourceLineNo">2115</span>   * @param compaction Compaction details, obtained by requestCompaction()<a name="line.2115"></a>
+<span class="sourceLineNo">2116</span>   * @param throughputController<a name="line.2116"></a>
+<span class="sourceLineNo">2117</span>   * @return whether the compaction completed<a name="line.2117"></a>
+<span class="sourceLineNo">2118</span>   */<a name="line.2118"></a>
+<span class="sourceLineNo">2119</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2119"></a>
+<span class="sourceLineNo">2120</span>      ThroughputController throughputController) throws IOException {<a name="line.2120"></a>
+<span class="sourceLineNo">2121</span>    return compact(compaction, store, throughputController, null);<a name="line.2121"></a>
+<span class="sourceLineNo">2122</span>  }<a name="line.2122"></a>
+<span class="sourceLineNo">2123</span><a name="line.2123"></a>
+<span class="sourceLineNo">2124</span>  private boolean shouldForbidMajorCompaction() {<a name="line.2124"></a>
+<span class="sourceLineNo">2125</span>    if (rsServices != null &amp;&amp; rsServices.getReplicationSourceService() != null) {<a name="line.2125"></a>
+<span class="sourceLineNo">2126</span>      return rsServices.getReplicationSourceService().getSyncReplicationPeerInfoProvider()<a name="line.2126"></a>
+<span class="sourceLineNo">2127</span>          .checkState(getRegionInfo().getTable(), ForbidMajorCompactionChecker.get());<a name="line.2127"></a>
+<span class="sourceLineNo">2128</span>    }<a name="line.2128"></a>
+<span class="sourceLineNo">2129</span>    return false;<a name="line.2129"></a>
+<span class="sourceLineNo">2130</span>  }<a name="line.2130"></a>
+<span class="sourceLineNo">2131</span><a name="line.2131"></a>
+<span class="sourceLineNo">2132</span>  /**<a name="line.2132"></a>
+<span class="sourceLineNo">2133</span>   * We are trying to remove / relax the region read lock for compaction.<a name="line.2133"></a>
+<span class="sourceLineNo">2134</span>   * Let's see what are the potential race conditions among the operations (user scan,<a name="line.2134"></a>
+<span class="sourceLineNo">2135</span>   * region split, region close and region bulk load).<a name="line.2135"></a>
+<span class="sourceLineNo">2136</span>   *<a name="line.2136"></a>
+<span class="sourceLineNo">2137</span>   *  user scan ---&gt; region read lock<a name="line.2137"></a>
+<span class="sourceLineNo">2138</span>   *  region split --&gt; region close first --&gt; region write lock<a name="line.2138"></a>
+<span class="sourceLineNo">2139</span>   *  region close --&gt; region write lock<a name="line.2139"></a>
+<span class="sourceLineNo">2140</span>   *  region bulk load --&gt; region write lock<a name="line.2140"></a>
+<span class="sourceLineNo">2141</span>   *<a name="line.2141"></a>
+<span class="sourceLineNo">2142</span>   * read lock is compatible with read lock. ---&gt; no problem with user scan/read<a name="line.2142"></a>
+<span class="sourceLineNo">2143</span>   * region bulk load does not cause problem for compaction (no consistency problem, store lock<a name="line.2143"></a>
+<span class="sourceLineNo">2144</span>   * will help the store file accounting).<a name="line.2144"></a>
+<span class="sourceLineNo">2145</span>   * They can run almost concurrently at the region level.<a name="line.2145"></a>
+<span class="sourceLineNo">2146</span>   *<a name="line.2146"></a>
+<span class="sourceLineNo">2147</span>   * The only remaining race condition is between the region close and compaction.<a name="line.2147"></a>
+<span class="sourceLineNo">2148</span>   * So we will evaluate, below, how region close intervenes with compaction if compaction does<a name="line.2148"></a>
+<span class="sourceLineNo">2149</span>   * not acquire region read lock.<a name="line.2149"></a>
+<span class="sourceLineNo">2150</span>   *<a name="line.2150"></a>
+<span class="sourceLineNo">2151</span>   * Here are the steps for compaction:<a name="line.2151"></a>
+<span class="sourceLineNo">2152</span>   * 1. obtain list of StoreFile's<a name="line.2152"></a>
+<span class="sourceLineNo">2153</span>   * 2. create StoreFileScanner's based on list from #1<a name="line.2153"></a>
+<span class="sourceLineNo">2154</span>   * 3. perform compaction and save resulting files under tmp dir<a name="line.2154"></a>
+<span class="sourceLineNo">2155</span>   * 4. swap in compacted files<a name="line.2155"></a>
+<span class="sourceLineNo">2156</span>   *<a name="line.2156"></a>
+<span class="sourceLineNo">2157</span>   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better<a name="line.2157"></a>
+<span class="sourceLineNo">2158</span>   * For #2, we obtain smallest read point (for region) across all the Scanners (for both default<a name="line.2158"></a>
+<span class="sourceLineNo">2159</span>   * compactor and stripe compactor).<a name="line.2159"></a>
+<span class="sourceLineNo">2160</span>   * The read points are for user scans. Region keeps the read points for all currently open<a name="line.2160"></a>
+<span class="sourceLineNo">2161</span>   * user scanners.<a name="line.2161"></a>
+<span class="sourceLineNo">2162</span>   * Compaction needs to know the smallest read point so that during re-write of the hfiles,<a name="line.2162"></a>
+<span class="sourceLineNo">2163</span>   * it can remove the mvcc points for the cells if their mvccs are older than the smallest<a name="line.2163"></a>
+<span class="sourceLineNo">2164</span>   * since they are not needed anymore.<a name="line.2164"></a>
+<span class="sourceLineNo">2165</span>   * This will not conflict with compaction.<a name="line.2165"></a>
+<span class="sourceLineNo">2166</span>   * For #3, it can be performed in parallel to other operations.<a name="line.2166"></a>
+<span class="sourceLineNo">2167</span>   * For #4 bulk load and compaction don't conflict with each other on the region level<a name="line.2167"></a>
+<span class="sourceLineNo">2168</span>   *   (for multi-family atomicy).<a name="line.2168"></a>
+<span class="sourceLineNo">2169</span>   * Region close and compaction are guarded pretty well by the 'writestate'.<a name="line.2169"></a>
+<span class="sourceLineNo">2170</span>   * In HRegion#doClose(), we have :<a name="line.2170"></a>
+<span class="sourceLineNo">2171</span>   * synchronized (writestate) {<a name="line.2171"></a>
+<span class="sourceLineNo">2172</span>   *   // Disable compacting and flushing by background threads for this<a name="line.2172"></a>
+<span class="sourceLineNo">2173</span>   *   // region.<a name="line.2173"></a>
+<span class="sourceLineNo">2174</span>   *   canFlush = !writestate.readOnly;<a name="line.2174"></a>
+<span class="sourceLineNo">2175</span>   *   writestate.writesEnabled = false;<a name="line.2175"></a>
+<span class="sourceLineNo">2176</span>   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");<a name="line.2176"></a>
+<span class="sourceLineNo">2177</span>   *   waitForFlushesAndCompactions();<a name="line.2177"></a>
+<span class="sourceLineNo">2178</span>   * }<a name="line.2178"></a>
+<span class="sourceLineNo">2179</span>   * waitForFlushesAndCompactions() would wait for writestate.compacting to come down to 0.<a name="line.2179"></a>
+<span class="sourceLineNo">2180</span>   * and in HRegion.compact()<a name="line.2180"></a>
+<span class="sourceLineNo">2181</span>   *  try {<a name="line.2181"></a>
+<span class="sourceLineNo">2182</span>   *    synchronized (writestate) {<a name="line.2182"></a>
+<span class="sourceLineNo">2183</span>   *    if (writestate.writesEnabled) {<a name="line.2183"></a>
+<span class="sourceLineNo">2184</span>   *      wasStateSet = true;<a name="line.2184"></a>
+<span class="sourceLineNo">2185</span>   *      ++writestate.compacting;<a name="line.2185"></a>
+<span class="sourceLineNo">2186</span>   *    } else {<a name="line.2186"></a>
+<span class="sourceLineNo">2187</span>   *      String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2187"></a>
+<span class="sourceLineNo">2188</span>   *      LOG.info(msg);<a name="line.2188"></a>
+<span class="sourceLineNo">2189</span>   *      status.abort(msg);<a name="line.2189"></a>
+<span class="sourceLineNo">2190</span>   *      return false;<a name="line.2190"></a>
+<span class="sourceLineNo">2191</span>   *    }<a name="line.2191"></a>
+<span class="sourceLineNo">2192</span>   *  }<a name="line.2192"></a>
+<span class="sourceLineNo">2193</span>   * Also in compactor.performCompaction():<a name="line.2193"></a>
+<span class="sourceLineNo">2194</span>   * check periodically to see if a system stop is requested<a name="line.2194"></a>
+<span class="sourceLineNo">2195</span>   * if (closeCheckInterval &gt; 0) {<a name="line.2195"></a>
+<span class="sourceLineNo">2196</span>   *   bytesWritten += len;<a name="line.2196"></a>
+<span class="sourceLineNo">2197</span>   *   if (bytesWritten &gt; closeCheckInterval) {<a name="line.2197"></a>
+<span class="sourceLineNo">2198</span>   *     bytesWritten = 0;<a name="line.2198"></a>
+<span class="sourceLineNo">2199</span>   *     if (!store.areWritesEnabled()) {<a name="line.2199"></a>
+<span class="sourceLineNo">2200</span>   *       progress.cancel();<a name="line.2200"></a>
+<span class="sourceLineNo">2201</span>   *       return false;<a name="line.2201"></a>
+<span class="sourceLineNo">2202</span>   *     }<a name="line.2202"></a>
+<span class="sourceLineNo">2203</span>   *   }<a name="line.2203"></a>
+<span class="sourceLineNo">2204</span>   * }<a name="line.2204"></a>
+<span class="sourceLineNo">2205</span>   */<a name="line.2205"></a>
+<span class="sourceLineNo">2206</span>  public boolean compact(CompactionContext compaction, HStore store,<a name="line.2206"></a>
+<span class="sourceLineNo">2207</span>      ThroughputController throughputController, User user) throws IOException {<a name="line.2207"></a>
+<span class="sourceLineNo">2208</span>    assert compaction != null &amp;&amp; compaction.hasSelection();<a name="line.2208"></a>
+<span class="sourceLineNo">2209</span>    assert !compaction.getRequest().getFiles().isEmpty();<a name="line.2209"></a>
+<span class="sourceLineNo">2210</span>    if (this.closing.get() || this.closed.get()) {<a name="line.2210"></a>
+<span class="sourceLineNo">2211</span>      LOG.debug("Skipping compaction on " + this + " because closing/closed");<a name="line.2211"></a>
+<span class="sourceLineNo">2212</span>      store.cancelRequestedCompaction(compaction);<a name="line.2212"></a>
+<span class="sourceLineNo">2213</span>      return false;<a name="line.2213"></a>
+<span class="sourceLineNo">2214</span>    }<a name="line.2214"></a>
+<span class="sourceLineNo">2215</span><a name="line.2215"></a>
+<span class="sourceLineNo">2216</span>    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {<a name="line.2216"></a>
+<span class="sourceLineNo">2217</span>      LOG.warn("Skipping major compaction on " + this<a name="line.2217"></a>
+<span class="sourceLineNo">2218</span>          + " because this cluster is transiting sync replication state"<a name="line.2218"></a>
+<span class="sourceLineNo">2219</span>          + " from STANDBY to DOWNGRADE_ACTIVE");<a name="line.2219"></a>
+<span class="sourceLineNo">2220</span>      store.cancelRequestedCompaction(compaction);<a name="line.2220"></a>
+<span class="sourceLineNo">2221</span>      return false;<a name="line.2221"></a>
+<span class="sourceLineNo">2222</span>    }<a name="line.2222"></a>
+<span class="sourceLineNo">2223</span><a name="line.2223"></a>
+<span class="sourceLineNo">2224</span>    MonitoredTask status = null;<a name="line.2224"></a>
+<span class="sourceLineNo">2225</span>    boolean requestNeedsCancellation = true;<a name="line.2225"></a>
+<span class="sourceLineNo">2226</span>    try {<a name="line.2226"></a>
+<span class="sourceLineNo">2227</span>      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());<a name="line.2227"></a>
+<span class="sourceLineNo">2228</span>      if (stores.get(cf) != store) {<a name="line.2228"></a>
+<span class="sourceLineNo">2229</span>        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this<a name="line.2229"></a>
+<span class="sourceLineNo">2230</span>            + " has been re-instantiated, cancel this compaction request. "<a name="line.2230"></a>
+<span class="sourceLineNo">2231</span>            + " It may be caused by the roll back of split transaction");<a name="line.2231"></a>
+<span class="sourceLineNo">2232</span>        return false;<a name="line.2232"></a>
+<span class="sourceLineNo">2233</span>      }<a name="line.2233"></a>
+<span class="sourceLineNo">2234</span><a name="line.2234"></a>
+<span class="sourceLineNo">2235</span>      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);<a name="line.2235"></a>
+<span class="sourceLineNo">2236</span>      status.enableStatusJournal(false);<a name="line.2236"></a>
+<span class="sourceLineNo">2237</span>      if (this.closed.get()) {<a name="line.2237"></a>
+<span class="sourceLineNo">2238</span>        String msg = "Skipping compaction on " + this + " because closed";<a name="line.2238"></a>
+<span class="sourceLineNo">2239</span>        LOG.debug(msg);<a name="line.2239"></a>
+<span class="sourceLineNo">2240</span>        status.abort(msg);<a name="line.2240"></a>
+<span class="sourceLineNo">2241</span>        return false;<a name="line.2241"></a>
+<span class="sourceLineNo">2242</span>      }<a name="line.2242"></a>
+<span class="sourceLineNo">2243</span>      boolean wasStateSet = false;<a name="line.2243"></a>
+<span class="sourceLineNo">2244</span>      try {<a name="line.2244"></a>
+<span class="sourceLineNo">2245</span>        synchronized (writestate) {<a name="line.2245"></a>
+<span class="sourceLineNo">2246</span>          if (writestate.writesEnabled) {<a name="line.2246"></a>
+<span class="sourceLineNo">2247</span>            wasStateSet = true;<a name="line.2247"></a>
+<span class="sourceLineNo">2248</span>            writestate.compacting.incrementAndGet();<a name="line.2248"></a>
+<span class="sourceLineNo">2249</span>          } else {<a name="line.2249"></a>
+<span class="sourceLineNo">2250</span>            String msg = "NOT compacting region " + this + ". Writes disabled.";<a name="line.2250"></a>
+<span class="sourceLineNo">2251</span>            LOG.info(msg);<a name="line.2251"></a>
+<span class="sourceLineNo">2252</span>            status.abort(msg);<a name="line.2252"></a>
+<span class="sourceLineNo">2253</span>            return false;<a name="line.2253"></a>
+<span class="sourceLineNo">2254</span>          }<a name="line.2254"></a>
+<span class="sourceLineNo">2255</span>        }<a name="line.2255"></a>
+<span class="sourceLineNo">2256</span>        LOG.info("Starting compaction of {} in {}{}", store, this,<a name="line.2256"></a>
+<span class="sourceLineNo">2257</span>            (compaction.getRequest().isOffPeak()?" as an off-peak compaction":""));<a name="line.2257"></a>
+<span class="sourceLineNo">2258</span>        doRegionCompactionPrep();<a name="line.2258"></a>
+<span class="sourceLineNo">2259</span>        try {<a name="line.2259"></a>
+<span class="sourceLineNo">2260</span>          status.setStatus("Compacting store " + store);<a name="line.2260"></a>
+<span class="sourceLineNo">2261</span>          // We no longer need to cancel the request on the way out of this<a name="line.2261"></a>
+<span class="sourceLineNo">2262</span>          // method because Store#compact will clean up unconditionally<a name="line.2262"></a>
+<span class="sourceLineNo">2263</span>          requestNeedsCancellation = false;<a name="line.2263"></a>
+<span class="sourceLineNo">2264</span>          store.compact(compaction, throughputController, user);<a name="line.2264"></a>
+<span class="sourceLineNo">2265</span>        } catch (InterruptedIOException iioe) {<a name="line.2265"></a>
+<span class="sourceLineNo">2266</span>          String msg = "compaction interrupted";<a name="line.2266"></a>
+<span class="sourceLineNo">2267</span>          LOG.info(msg, iioe);<a name="line.2267"></a>
+<span class="sourceLineNo">2268</span>          status.abort(msg);<a name="line.2268"></a>
+<span class="sourceLineNo">2269</span>          return false;<a name="line.2269"></a>
+<span class="sourceLineNo">2270</span>        }<a name="line.2270"></a>
+<span class="sourceLineNo">2271</span>      } finally {<a name="line.2271"></a>
+<span class="sourceLineNo">2272</span>        if (wasStateSet) {<a name="line.2272"></a>
+<span class="sourceLineNo">2273</span>          synchronized (writestate) {<a name="line.2273"></a>
+<span class="sourceLineNo">2274</span>            writestate.compacting.decrementAndGet();<a name="line.2274"></a>
+<span class="sourceLineNo">2275</span>            if (writestate.compacting.get() &lt;= 0) {<a name="line.2275"></a>
+<span class="sourceLineNo">2276</span>              writestate.notifyAll();<a name="line.2276"></a>
+<span class="sourceLineNo">2277</span>            }<a name="line.2277"></a>
+<span class="sourceLineNo">2278</span>          }<a name="line.2278"></a>
+<span class="sourceLineNo">2279</span>        }<a name="line.2279"></a>
+<span class="sourceLineNo">2280</span>      }<a name="line.2280"></a>
+<span class="sourceLineNo">2281</span>      status.markComplete("Compaction complete");<a name="line.2281"></a>
+<span class="sourceLineNo">2282</span>      return true;<a name="line.2282"></a>
+<span class="sourceLineNo">2283</span>    } finally {<a name="line.2283"></a>
+<span class="sourceLineNo">2284</span>      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);<a name="line.2284"></a>
+<span class="sourceLineNo">2285</span>      if (status != null) {<a name="line.2285"></a>
+<span class="sourceLineNo">2286</span>        LOG.debug("Compaction status journal:\n\t" + status.prettyPrintJournal());<a name="line.2286"></a>
+<span class="sourceLineNo">2287</span>        status.cleanup();<a name="line.2287"></a>
+<span class="sourceLineNo">2288</span>      }<a name="line.2288"></a>
+<span class="sourceLineNo">2289</span>    }<a name="line.2289"></a>
+<span class="sourceLineNo">2290</span>  }<a name="line.2290"></a>
+<span class="sourceLineNo">2291</span><a name="line.2291"></a>
+<span class="sourceLineNo">2292</span>  /**<a name="line.2292"></a>
+<span class="sourceLineNo">2293</span>   * Flush the cache.<a name="line.2293"></a>
+<span class="sourceLineNo">2294</span>   *<a name="line.2294"></a>
+<span class="sourceLineNo">2295</span>   * &lt;p&gt;When this method is called the cache will be flushed unless:<a name="line.2295"></a>
+<span class="sourceLineNo">2296</span>   * &lt;ol&gt;<a name="line.2296"></a>
+<span class="sourceLineNo">2297</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2297"></a>
+<span class="sourceLineNo">2298</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2298"></a>
+<span class="sourceLineNo">2299</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2299"></a>
+<span class="sourceLineNo">2300</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2300"></a>
+<span class="sourceLineNo">2301</span>   * &lt;/ol&gt;<a name="line.2301"></a>
+<span class="sourceLineNo">2302</span>   *<a name="line.2302"></a>
+<span class="sourceLineNo">2303</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2303"></a>
+<span class="sourceLineNo">2304</span>   * time-sensitive thread.<a name="line.2304"></a>
+<span class="sourceLineNo">2305</span>   * @param force whether we want to force a flush of all stores<a name="line.2305"></a>
+<span class="sourceLineNo">2306</span>   * @return FlushResult indicating whether the flush was successful or not and if<a name="line.2306"></a>
+<span class="sourceLineNo">2307</span>   * the region needs compacting<a name="line.2307"></a>
+<span class="sourceLineNo">2308</span>   *<a name="line.2308"></a>
+<span class="sourceLineNo">2309</span>   * @throws IOException general io exceptions<a name="line.2309"></a>
+<span class="sourceLineNo">2310</span>   * because a snapshot was not properly persisted.<a name="line.2310"></a>
+<span class="sourceLineNo">2311</span>   */<a name="line.2311"></a>
+<span class="sourceLineNo">2312</span>  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs<a name="line.2312"></a>
+<span class="sourceLineNo">2313</span>  public FlushResult flush(boolean force) throws IOException {<a name="line.2313"></a>
+<span class="sourceLineNo">2314</span>    return flushcache(force, false, FlushLifeCycleTracker.DUMMY);<a name="line.2314"></a>
+<span class="sourceLineNo">2315</span>  }<a name="line.2315"></a>
+<span class="sourceLineNo">2316</span><a name="line.2316"></a>
+<span class="sourceLineNo">2317</span>  public interface FlushResult {<a name="line.2317"></a>
+<span class="sourceLineNo">2318</span>    enum Result {<a name="line.2318"></a>
+<span class="sourceLineNo">2319</span>      FLUSHED_NO_COMPACTION_NEEDED,<a name="line.2319"></a>
+<span class="sourceLineNo">2320</span>      FLUSHED_COMPACTION_NEEDED,<a name="line.2320"></a>
+<span class="sourceLineNo">2321</span>      // Special case where a flush didn't run because there's nothing in the memstores. Used when<a name="line.2321"></a>
+<span class="sourceLineNo">2322</span>      // bulk loading to know when we can still load even if a flush didn't happen.<a name="line.2322"></a>
+<span class="sourceLineNo">2323</span>      CANNOT_FLUSH_MEMSTORE_EMPTY,<a name="line.2323"></a>
+<span class="sourceLineNo">2324</span>      CANNOT_FLUSH<a name="line.2324"></a>
+<span class="sourceLineNo">2325</span>    }<a name="line.2325"></a>
 <span class="sourceLineNo">2326</span><a name="line.2326"></a>
-<span class="sourceLineNo">2327</span>    /** @return true if the memstores were flushed, else false */<a name="line.2327"></a>
-<span class="sourceLineNo">2328</span>    boolean isFlushSucceeded();<a name="line.2328"></a>
+<span class="sourceLineNo">2327</span>    /** @return the detailed result code */<a name="line.2327"></a>
+<span class="sourceLineNo">2328</span>    Result getResult();<a name="line.2328"></a>
 <span class="sourceLineNo">2329</span><a name="line.2329"></a>
-<span class="sourceLineNo">2330</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2330"></a>
-<span class="sourceLineNo">2331</span>    boolean isCompactionNeeded();<a name="line.2331"></a>
-<span class="sourceLineNo">2332</span>  }<a name="line.2332"></a>
-<span class="sourceLineNo">2333</span><a name="line.2333"></a>
-<span class="sourceLineNo">2334</span>  /**<a name="line.2334"></a>
-<span class="sourceLineNo">2335</span>   * Flush the cache.<a name="line.2335"></a>
-<span class="sourceLineNo">2336</span>   *<a name="line.2336"></a>
-<span class="sourceLineNo">2337</span>   * When this method is called the cache will be flushed unless:<a name="line.2337"></a>
-<span class="sourceLineNo">2338</span>   * &lt;ol&gt;<a name="line.2338"></a>
-<span class="sourceLineNo">2339</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2339"></a>
-<span class="sourceLineNo">2340</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2340"></a>
-<span class="sourceLineNo">2341</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2341"></a>
-<span class="sourceLineNo">2342</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2342"></a>
-<span class="sourceLineNo">2343</span>   * &lt;/ol&gt;<a name="line.2343"></a>
-<span class="sourceLineNo">2344</span>   *<a name="line.2344"></a>
-<span class="sourceLineNo">2345</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2345"></a>
-<span class="sourceLineNo">2346</span>   * time-sensitive thread.<a name="line.2346"></a>
-<span class="sourceLineNo">2347</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2347"></a>
-<span class="sourceLineNo">2348</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2348"></a>
-<span class="sourceLineNo">2349</span>   * @param tracker used to track the life cycle of this flush<a name="line.2349"></a>
-<span class="sourceLineNo">2350</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2350"></a>
-<span class="sourceLineNo">2351</span>   *<a name="line.2351"></a>
-<span class="sourceLineNo">2352</span>   * @throws IOException general io exceptions<a name="line.2352"></a>
-<span class="sourceLineNo">2353</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2353"></a>
-<span class="sourceLineNo">2354</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2354"></a>
-<span class="sourceLineNo">2355</span>   * caller MUST abort after this.<a name="line.2355"></a>
-<span class="sourceLineNo">2356</span>   */<a name="line.2356"></a>
-<span class="sourceLineNo">2357</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2357"></a>
-<span class="sourceLineNo">2358</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2358"></a>
-<span class="sourceLineNo">2359</span>    // fail-fast instead of waiting on the lock<a name="line.2359"></a>
-<span class="sourceLineNo">2360</span>    if (this.closing.get()) {<a name="line.2360"></a>
-<span class="sourceLineNo">2361</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2361"></a>
-<span class="sourceLineNo">2362</span>      LOG.debug(msg);<a name="line.2362"></a>
-<span class="sourceLineNo">2363</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2363"></a>
-<span class="sourceLineNo">2364</span>    }<a name="line.2364"></a>
-<span class="sourceLineNo">2365</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2365"></a>
-<span class="sourceLineNo">2366</span>    status.enableStatusJournal(false);<a name="line.2366"></a>
-<span class="sourceLineNo">2367</span>    status.setStatus("Acquiring readlock on region");<a name="line.2367"></a>
-<span class="sourceLineNo">2368</span>    // block waiting for the lock for flushing cache<a name="line.2368"></a>
-<span class="sourceLineNo">2369</span>    lock.readLock().lock();<a name="line.2369"></a>
-<span class="sourceLineNo">2370</span>    try {<a name="line.2370"></a>
-<span class="sourceLineNo">2371</span>      if (this.closed.get()) {<a name="line.2371"></a>
-<span class="sourceLineNo">2372</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2372"></a>
-<span class="sourceLineNo">2373</span>        LOG.debug(msg);<a name="line.2373"></a>
-<span class="sourceLineNo">2374</span>        status.abort(msg);<a name="line.2374"></a>
-<span class="sourceLineNo">2375</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2375"></a>
-<span class="sourceLineNo">2376</span>      }<a name="line.2376"></a>
-<span class="sourceLineNo">2377</span>      if (coprocessorHost != null) {<a name="line.2377"></a>
-<span class="sourceLineNo">2378</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2378"></a>
-<span class="sourceLineNo">2379</span>        coprocessorHost.preFlush(tracker);<a name="line.2379"></a>
-<span class="sourceLineNo">2380</span>      }<a name="line.2380"></a>
-<span class="sourceLineNo">2381</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2381"></a>
-<span class="sourceLineNo">2382</span>      // successful<a name="line.2382"></a>
-<span class="sourceLineNo">2383</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2383"></a>
-<span class="sourceLineNo">2384</span>        numMutationsWithoutWAL.reset();<a name="line.2384"></a>
-<span class="sourceLineNo">2385</span>        dataInMemoryWithoutWAL.reset();<a name="line.2385"></a>
-<span class="sourceLineNo">2386</span>      }<a name="line.2386"></a>
-<span class="sourceLineNo">2387</span>      synchronized (writestate) {<a name="line.2387"></a>
-<span class="sourceLineNo">2388</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2388"></a>
-<span class="sourceLineNo">2389</span>          this.writestate.flushing = true;<a name="line.2389"></a>
-<span class="sourceLineNo">2390</span>        } else {<a name="line.2390"></a>
-<span class="sourceLineNo">2391</span>          if (LOG.isDebugEnabled()) {<a name="line.2391"></a>
-<span class="sourceLineNo">2392</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2392"></a>
-<span class="sourceLineNo">2393</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2393"></a>
-<span class="sourceLineNo">2394</span>                + writestate.writesEnabled);<a name="line.2394"></a>
-<span class="sourceLineNo">2395</span>          }<a name="line.2395"></a>
-<span class="sourceLineNo">2396</span>          String msg = "Not flushing since "<a name="line.2396"></a>
-<span class="sourceLineNo">2397</span>              + (writestate.flushing ? "already flushing"<a name="line.2397"></a>
-<span class="sourceLineNo">2398</span>              : "writes not enabled");<a name="line.2398"></a>
-<span class="sourceLineNo">2399</span>          status.abort(msg);<a name="line.2399"></a>
-<span class="sourceLineNo">2400</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2400"></a>
-<span class="sourceLineNo">2401</span>        }<a name="line.2401"></a>
-<span class="sourceLineNo">2402</span>      }<a name="line.2402"></a>
-<span class="sourceLineNo">2403</span><a name="line.2403"></a>
-<span class="sourceLineNo">2404</span>      try {<a name="line.2404"></a>
-<span class="sourceLineNo">2405</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2405"></a>
-<span class="sourceLineNo">2406</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2406"></a>
-<span class="sourceLineNo">2407</span>        FlushResultImpl fs =<a name="line.2407"></a>
-<span class="sourceLineNo">2408</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2408"></a>
-<span class="sourceLineNo">2409</span><a name="line.2409"></a>
-<span class="sourceLineNo">2410</span>        if (coprocessorHost != null) {<a name="line.2410"></a>
-<span class="sourceLineNo">2411</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2411"></a>
-<span class="sourceLineNo">2412</span>          coprocessorHost.postFlush(tracker);<a name="line.2412"></a>
-<span class="sourceLineNo">2413</span>        }<a name="line.2413"></a>
-<span class="sourceLineNo">2414</span><a name="line.2414"></a>
-<span class="sourceLineNo">2415</span>        if(fs.isFlushSucceeded()) {<a name="line.2415"></a>
-<span class="sourceLineNo">2416</span>          flushesQueued.reset();<a name="line.2416"></a>
-<span class="sourceLineNo">2417</span>        }<a name="line.2417"></a>
-<span class="sourceLineNo">2418</span><a name="line.2418"></a>
-<span class="sourceLineNo">2419</span>        status.markComplete("Flush successful");<a name="line.2419"></a>
-<span class="sourceLineNo">2420</span>        return fs;<a name="line.2420"></a>
-<span class="sourceLineNo">2421</span>      } finally {<a name="line.2421"></a>
-<span class="sourceLineNo">2422</span>        synchronized (writestate) {<a name="line.2422"></a>
-<span class="sourceLineNo">2423</span>          writestate.flushing = false;<a name="line.2423"></a>
-<span class="sourceLineNo">2424</span>          this.writestate.flushRequested = false;<a name="line.2424"></a>
-<span class="sourceLineNo">2425</span>          writestate.notifyAll();<a name="line.2425"></a>
-<span class="sourceLineNo">2426</span>        }<a name="line.2426"></a>
-<span class="sourceLineNo">2427</span>      }<a name="line.2427"></a>
-<span class="sourceLineNo">2428</span>    } finally {<a name="line.2428"></a>
-<span class="sourceLineNo">2429</span>      lock.readLock().unlock();<a name="line.2429"></a>
-<span class="sourceLineNo">2430</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2430"></a>
-<span class="sourceLineNo">2431</span>      status.cleanup();<a name="line.2431"></a>
-<span class="sourceLineNo">2432</span>    }<a name="line.2432"></a>
-<span class="sourceLineNo">2433</span>  }<a name="line.2433"></a>
-<span class="sourceLineNo">2434</span><a name="line.2434"></a>
-<span class="sourceLineNo">2435</span>  /**<a name="line.2435"></a>
-<span class="sourceLineNo">2436</span>   * Should the store be flushed because it is old enough.<a name="line.2436"></a>
-<span class="sourceLineNo">2437</span>   * &lt;p&gt;<a name="line.2437"></a>
-<span class="sourceLineNo">2438</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2438"></a>
-<span class="sourceLineNo">2439</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2439"></a>
-<span class="sourceLineNo">2440</span>   * returns true which will make a lot of flush requests.<a name="line.2440"></a>
-<span class="sourceLineNo">2441</span>   */<a name="line.2441"></a>
-<span class="sourceLineNo">2442</span>  boolean shouldFlushStore(HStore store) {<a name="line.2442"></a>
-<span class="sourceLineNo">2443</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2443"></a>
-<span class="sourceLineNo">2444</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2444"></a>
-<span class="sourceLineNo">2445</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2445"></a>
-<span class="sourceLineNo">2446</span>      if (LOG.isDebugEnabled()) {<a name="line.2446"></a>
-<span class="sourceLineNo">2447</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2447"></a>
-<span class="sourceLineNo">2448</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2448"></a>
-<span class="sourceLineNo">2449</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2449"></a>
-<span class="sourceLineNo">2450</span>      }<a name="line.2450"></a>
-<span class="sourceLineNo">2451</span>      return true;<a name="line.2451"></a>
-<span class="sourceLineNo">2452</span>    }<a name="line.2452"></a>
-<span class="sourceLineNo">2453</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2453"></a>
-<span class="sourceLineNo">2454</span>      return false;<a name="line.2454"></a>
+<span class="sourceLineNo">2330</span>    /** @return true if the memstores were flushed, else false */<a name="line.2330"></a>
+<span class="sourceLineNo">2331</span>    boolean isFlushSucceeded();<a name="line.2331"></a>
+<span class="sourceLineNo">2332</span><a name="line.2332"></a>
+<span class="sourceLineNo">2333</span>    /** @return True if the flush requested a compaction, else false */<a name="line.2333"></a>
+<span class="sourceLineNo">2334</span>    boolean isCompactionNeeded();<a name="line.2334"></a>
+<span class="sourceLineNo">2335</span>  }<a name="line.2335"></a>
+<span class="sourceLineNo">2336</span><a name="line.2336"></a>
+<span class="sourceLineNo">2337</span>  /**<a name="line.2337"></a>
+<span class="sourceLineNo">2338</span>   * Flush the cache.<a name="line.2338"></a>
+<span class="sourceLineNo">2339</span>   *<a name="line.2339"></a>
+<span class="sourceLineNo">2340</span>   * When this method is called the cache will be flushed unless:<a name="line.2340"></a>
+<span class="sourceLineNo">2341</span>   * &lt;ol&gt;<a name="line.2341"></a>
+<span class="sourceLineNo">2342</span>   *   &lt;li&gt;the cache is empty&lt;/li&gt;<a name="line.2342"></a>
+<span class="sourceLineNo">2343</span>   *   &lt;li&gt;the region is closed.&lt;/li&gt;<a name="line.2343"></a>
+<span class="sourceLineNo">2344</span>   *   &lt;li&gt;a flush is already in progress&lt;/li&gt;<a name="line.2344"></a>
+<span class="sourceLineNo">2345</span>   *   &lt;li&gt;writes are disabled&lt;/li&gt;<a name="line.2345"></a>
+<span class="sourceLineNo">2346</span>   * &lt;/ol&gt;<a name="line.2346"></a>
+<span class="sourceLineNo">2347</span>   *<a name="line.2347"></a>
+<span class="sourceLineNo">2348</span>   * &lt;p&gt;This method may block for some time, so it should not be called from a<a name="line.2348"></a>
+<span class="sourceLineNo">2349</span>   * time-sensitive thread.<a name="line.2349"></a>
+<span class="sourceLineNo">2350</span>   * @param forceFlushAllStores whether we want to flush all stores<a name="line.2350"></a>
+<span class="sourceLineNo">2351</span>   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL<a name="line.2351"></a>
+<span class="sourceLineNo">2352</span>   * @param tracker used to track the life cycle of this flush<a name="line.2352"></a>
+<span class="sourceLineNo">2353</span>   * @return whether the flush is success and whether the region needs compacting<a name="line.2353"></a>
+<span class="sourceLineNo">2354</span>   *<a name="line.2354"></a>
+<span class="sourceLineNo">2355</span>   * @throws IOException general io exceptions<a name="line.2355"></a>
+<span class="sourceLineNo">2356</span>   * @throws DroppedSnapshotException Thrown when replay of wal is required<a name="line.2356"></a>
+<span class="sourceLineNo">2357</span>   * because a Snapshot was not properly persisted. The region is put in closing mode, and the<a name="line.2357"></a>
+<span class="sourceLineNo">2358</span>   * caller MUST abort after this.<a name="line.2358"></a>
+<span class="sourceLineNo">2359</span>   */<a name="line.2359"></a>
+<span class="sourceLineNo">2360</span>  public FlushResultImpl flushcache(boolean forceFlushAllStores, boolean writeFlushRequestWalMarker,<a name="line.2360"></a>
+<span class="sourceLineNo">2361</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2361"></a>
+<span class="sourceLineNo">2362</span>    // fail-fast instead of waiting on the lock<a name="line.2362"></a>
+<span class="sourceLineNo">2363</span>    if (this.closing.get()) {<a name="line.2363"></a>
+<span class="sourceLineNo">2364</span>      String msg = "Skipping flush on " + this + " because closing";<a name="line.2364"></a>
+<span class="sourceLineNo">2365</span>      LOG.debug(msg);<a name="line.2365"></a>
+<span class="sourceLineNo">2366</span>      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2366"></a>
+<span class="sourceLineNo">2367</span>    }<a name="line.2367"></a>
+<span class="sourceLineNo">2368</span>    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);<a name="line.2368"></a>
+<span class="sourceLineNo">2369</span>    status.enableStatusJournal(false);<a name="line.2369"></a>
+<span class="sourceLineNo">2370</span>    status.setStatus("Acquiring readlock on region");<a name="line.2370"></a>
+<span class="sourceLineNo">2371</span>    // block waiting for the lock for flushing cache<a name="line.2371"></a>
+<span class="sourceLineNo">2372</span>    lock.readLock().lock();<a name="line.2372"></a>
+<span class="sourceLineNo">2373</span>    try {<a name="line.2373"></a>
+<span class="sourceLineNo">2374</span>      if (this.closed.get()) {<a name="line.2374"></a>
+<span class="sourceLineNo">2375</span>        String msg = "Skipping flush on " + this + " because closed";<a name="line.2375"></a>
+<span class="sourceLineNo">2376</span>        LOG.debug(msg);<a name="line.2376"></a>
+<span class="sourceLineNo">2377</span>        status.abort(msg);<a name="line.2377"></a>
+<span class="sourceLineNo">2378</span>        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2378"></a>
+<span class="sourceLineNo">2379</span>      }<a name="line.2379"></a>
+<span class="sourceLineNo">2380</span>      if (coprocessorHost != null) {<a name="line.2380"></a>
+<span class="sourceLineNo">2381</span>        status.setStatus("Running coprocessor pre-flush hooks");<a name="line.2381"></a>
+<span class="sourceLineNo">2382</span>        coprocessorHost.preFlush(tracker);<a name="line.2382"></a>
+<span class="sourceLineNo">2383</span>      }<a name="line.2383"></a>
+<span class="sourceLineNo">2384</span>      // TODO: this should be managed within memstore with the snapshot, updated only after flush<a name="line.2384"></a>
+<span class="sourceLineNo">2385</span>      // successful<a name="line.2385"></a>
+<span class="sourceLineNo">2386</span>      if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.2386"></a>
+<span class="sourceLineNo">2387</span>        numMutationsWithoutWAL.reset();<a name="line.2387"></a>
+<span class="sourceLineNo">2388</span>        dataInMemoryWithoutWAL.reset();<a name="line.2388"></a>
+<span class="sourceLineNo">2389</span>      }<a name="line.2389"></a>
+<span class="sourceLineNo">2390</span>      synchronized (writestate) {<a name="line.2390"></a>
+<span class="sourceLineNo">2391</span>        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {<a name="line.2391"></a>
+<span class="sourceLineNo">2392</span>          this.writestate.flushing = true;<a name="line.2392"></a>
+<span class="sourceLineNo">2393</span>        } else {<a name="line.2393"></a>
+<span class="sourceLineNo">2394</span>          if (LOG.isDebugEnabled()) {<a name="line.2394"></a>
+<span class="sourceLineNo">2395</span>            LOG.debug("NOT flushing memstore for region " + this<a name="line.2395"></a>
+<span class="sourceLineNo">2396</span>                + ", flushing=" + writestate.flushing + ", writesEnabled="<a name="line.2396"></a>
+<span class="sourceLineNo">2397</span>                + writestate.writesEnabled);<a name="line.2397"></a>
+<span class="sourceLineNo">2398</span>          }<a name="line.2398"></a>
+<span class="sourceLineNo">2399</span>          String msg = "Not flushing since "<a name="line.2399"></a>
+<span class="sourceLineNo">2400</span>              + (writestate.flushing ? "already flushing"<a name="line.2400"></a>
+<span class="sourceLineNo">2401</span>              : "writes not enabled");<a name="line.2401"></a>
+<span class="sourceLineNo">2402</span>          status.abort(msg);<a name="line.2402"></a>
+<span class="sourceLineNo">2403</span>          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);<a name="line.2403"></a>
+<span class="sourceLineNo">2404</span>        }<a name="line.2404"></a>
+<span class="sourceLineNo">2405</span>      }<a name="line.2405"></a>
+<span class="sourceLineNo">2406</span><a name="line.2406"></a>
+<span class="sourceLineNo">2407</span>      try {<a name="line.2407"></a>
+<span class="sourceLineNo">2408</span>        Collection&lt;HStore&gt; specificStoresToFlush =<a name="line.2408"></a>
+<span class="sourceLineNo">2409</span>            forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush();<a name="line.2409"></a>
+<span class="sourceLineNo">2410</span>        FlushResultImpl fs =<a name="line.2410"></a>
+<span class="sourceLineNo">2411</span>            internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);<a name="line.2411"></a>
+<span class="sourceLineNo">2412</span><a name="line.2412"></a>
+<span class="sourceLineNo">2413</span>        if (coprocessorHost != null) {<a name="line.2413"></a>
+<span class="sourceLineNo">2414</span>          status.setStatus("Running post-flush coprocessor hooks");<a name="line.2414"></a>
+<span class="sourceLineNo">2415</span>          coprocessorHost.postFlush(tracker);<a name="line.2415"></a>
+<span class="sourceLineNo">2416</span>        }<a name="line.2416"></a>
+<span class="sourceLineNo">2417</span><a name="line.2417"></a>
+<span class="sourceLineNo">2418</span>        if(fs.isFlushSucceeded()) {<a name="line.2418"></a>
+<span class="sourceLineNo">2419</span>          flushesQueued.reset();<a name="line.2419"></a>
+<span class="sourceLineNo">2420</span>        }<a name="line.2420"></a>
+<span class="sourceLineNo">2421</span><a name="line.2421"></a>
+<span class="sourceLineNo">2422</span>        status.markComplete("Flush successful");<a name="line.2422"></a>
+<span class="sourceLineNo">2423</span>        return fs;<a name="line.2423"></a>
+<span class="sourceLineNo">2424</span>      } finally {<a name="line.2424"></a>
+<span class="sourceLineNo">2425</span>        synchronized (writestate) {<a name="line.2425"></a>
+<span class="sourceLineNo">2426</span>          writestate.flushing = false;<a name="line.2426"></a>
+<span class="sourceLineNo">2427</span>          this.writestate.flushRequested = false;<a name="line.2427"></a>
+<span class="sourceLineNo">2428</span>          writestate.notifyAll();<a name="line.2428"></a>
+<span class="sourceLineNo">2429</span>        }<a name="line.2429"></a>
+<span class="sourceLineNo">2430</span>      }<a name="line.2430"></a>
+<span class="sourceLineNo">2431</span>    } finally {<a name="line.2431"></a>
+<span class="sourceLineNo">2432</span>      lock.readLock().unlock();<a name="line.2432"></a>
+<span class="sourceLineNo">2433</span>      LOG.debug("Flush status journal:\n\t" + status.prettyPrintJournal());<a name="line.2433"></a>
+<span class="sourceLineNo">2434</span>      status.cleanup();<a name="line.2434"></a>
+<span class="sourceLineNo">2435</span>    }<a name="line.2435"></a>
+<span class="sourceLineNo">2436</span>  }<a name="line.2436"></a>
+<span class="sourceLineNo">2437</span><a name="line.2437"></a>
+<span class="sourceLineNo">2438</span>  /**<a name="line.2438"></a>
+<span class="sourceLineNo">2439</span>   * Should the store be flushed because it is old enough.<a name="line.2439"></a>
+<span class="sourceLineNo">2440</span>   * &lt;p&gt;<a name="line.2440"></a>
+<span class="sourceLineNo">2441</span>   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except<a name="line.2441"></a>
+<span class="sourceLineNo">2442</span>   * that you always flush all stores). Otherwise the method will always<a name="line.2442"></a>
+<span class="sourceLineNo">2443</span>   * returns true which will make a lot of flush requests.<a name="line.2443"></a>
+<span class="sourceLineNo">2444</span>   */<a name="line.2444"></a>
+<span class="sourceLineNo">2445</span>  boolean shouldFlushStore(HStore store) {<a name="line.2445"></a>
+<span class="sourceLineNo">2446</span>    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),<a name="line.2446"></a>
+<span class="sourceLineNo">2447</span>      store.getColumnFamilyDescriptor().getName()) - 1;<a name="line.2447"></a>
+<span class="sourceLineNo">2448</span>    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {<a name="line.2448"></a>
+<span class="sourceLineNo">2449</span>      if (LOG.isDebugEnabled()) {<a name="line.2449"></a>
+<span class="sourceLineNo">2450</span>        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of " +<a name="line.2450"></a>
+<span class="sourceLineNo">2451</span>          getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest +<a name="line.2451"></a>
+<span class="sourceLineNo">2452</span>          " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());<a name="line.2452"></a>
+<span class="sourceLineNo">2453</span>      }<a name="line.2453"></a>
+<span class="sourceLineNo">2454</span>      return true;<a name="line.2454"></a>
 <span class="sourceLineNo">2455</span>    }<a name="line.2455"></a>
-<span class="sourceLineNo">2456</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2456"></a>
-<span class="sourceLineNo">2457</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2457"></a>
-<span class="sourceLineNo">2458</span>      if (LOG.isDebugEnabled()) {<a name="line.2458"></a>
-<span class="sourceLineNo">2459</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2459"></a>
-<span class="sourceLineNo">2460</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2460"></a>
-<span class="sourceLineNo">2461</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2461"></a>
-<span class="sourceLineNo">2462</span>      }<a name="line.2462"></a>
-<span class="sourceLineNo">2463</span>      return true;<a name="line.2463"></a>
-<span class="sourceLineNo">2464</span>    }<a name="line.2464"></a>
-<span class="sourceLineNo">2465</span>    return false;<a name="line.2465"></a>
-<span class="sourceLineNo">2466</span>  }<a name="line.2466"></a>
-<span class="sourceLineNo">2467</span><a name="line.2467"></a>
-<span class="sourceLineNo">2468</span>  /**<a name="line.2468"></a>
-<span class="sourceLineNo">2469</span>   * Should the memstore be flushed now<a name="line.2469"></a>
-<span class="sourceLineNo">2470</span>   */<a name="line.2470"></a>
-<span class="sourceLineNo">2471</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2471"></a>
-<span class="sourceLineNo">2472</span>    whyFlush.setLength(0);<a name="line.2472"></a>
-<span class="sourceLineNo">2473</span>    // This is a rough measure.<a name="line.2473"></a>
-<span class="sourceLineNo">2474</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2474"></a>
-<span class="sourceLineNo">2475</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2475"></a>
-<span class="sourceLineNo">2476</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2476"></a>
-<span class="sourceLineNo">2477</span>      return true;<a name="line.2477"></a>
-<span class="sourceLineNo">2478</span>    }<a name="line.2478"></a>
-<span class="sourceLineNo">2479</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2479"></a>
-<span class="sourceLineNo">2480</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2480"></a>
-<span class="sourceLineNo">2481</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2481"></a>
-<span class="sourceLineNo">2482</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2482"></a>
-<span class="sourceLineNo">2483</span>    }<a name="line.2483"></a>
-<span class="sourceLineNo">2484</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2484"></a>
-<span class="sourceLineNo">2485</span>      return false;<a name="line.2485"></a>
+<span class="sourceLineNo">2456</span>    if (this.flushCheckInterval &lt;= 0) {<a name="line.2456"></a>
+<span class="sourceLineNo">2457</span>      return false;<a name="line.2457"></a>
+<span class="sourceLineNo">2458</span>    }<a name="line.2458"></a>
+<span class="sourceLineNo">2459</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2459"></a>
+<span class="sourceLineNo">2460</span>    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {<a name="line.2460"></a>
+<span class="sourceLineNo">2461</span>      if (LOG.isDebugEnabled()) {<a name="line.2461"></a>
+<span class="sourceLineNo">2462</span>        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of " +<a name="line.2462"></a>
+<span class="sourceLineNo">2463</span>          getRegionInfo().getEncodedName() + " because time of oldest edit=" +<a name="line.2463"></a>
+<span class="sourceLineNo">2464</span>            store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);<a name="line.2464"></a>
+<span class="sourceLineNo">2465</span>      }<a name="line.2465"></a>
+<span class="sourceLineNo">2466</span>      return true;<a name="line.2466"></a>
+<span class="sourceLineNo">2467</span>    }<a name="line.2467"></a>
+<span class="sourceLineNo">2468</span>    return false;<a name="line.2468"></a>
+<span class="sourceLineNo">2469</span>  }<a name="line.2469"></a>
+<span class="sourceLineNo">2470</span><a name="line.2470"></a>
+<span class="sourceLineNo">2471</span>  /**<a name="line.2471"></a>
+<span class="sourceLineNo">2472</span>   * Should the memstore be flushed now<a name="line.2472"></a>
+<span class="sourceLineNo">2473</span>   */<a name="line.2473"></a>
+<span class="sourceLineNo">2474</span>  boolean shouldFlush(final StringBuilder whyFlush) {<a name="line.2474"></a>
+<span class="sourceLineNo">2475</span>    whyFlush.setLength(0);<a name="line.2475"></a>
+<span class="sourceLineNo">2476</span>    // This is a rough measure.<a name="line.2476"></a>
+<span class="sourceLineNo">2477</span>    if (this.maxFlushedSeqId &gt; 0<a name="line.2477"></a>
+<span class="sourceLineNo">2478</span>          &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())) {<a name="line.2478"></a>
+<span class="sourceLineNo">2479</span>      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");<a name="line.2479"></a>
+<span class="sourceLineNo">2480</span>      return true;<a name="line.2480"></a>
+<span class="sourceLineNo">2481</span>    }<a name="line.2481"></a>
+<span class="sourceLineNo">2482</span>    long modifiedFlushCheckInterval = flushCheckInterval;<a name="line.2482"></a>
+<span class="sourceLineNo">2483</span>    if (getRegionInfo().getTable().isSystemTable() &amp;&amp;<a name="line.2483"></a>
+<span class="sourceLineNo">2484</span>        getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) {<a name="line.2484"></a>
+<span class="sourceLineNo">2485</span>      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;<a name="line.2485"></a>
 <span class="sourceLineNo">2486</span>    }<a name="line.2486"></a>
-<span class="sourceLineNo">2487</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2487"></a>
-<span class="sourceLineNo">2488</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2488"></a>
-<span class="sourceLineNo">2489</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2489"></a>
-<span class="sourceLineNo">2490</span>      return false;<a name="line.2490"></a>
-<span class="sourceLineNo">2491</span>    }<a name="line.2491"></a>
-<span class="sourceLineNo">2492</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2492"></a>
-<span class="sourceLineNo">2493</span>    //are met. Return true on first such memstore hit.<a name="line.2493"></a>
-<span class="sourceLineNo">2494</span>    for (HStore s : stores.values()) {<a name="line.2494"></a>
-<span class="sourceLineNo">2495</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2495"></a>
-<span class="sourceLineNo">2496</span>        // we have an old enough edit in the memstore, flush<a name="line.2496"></a>
-<span class="sourceLineNo">2497</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2497"></a>
-<span class="sourceLineNo">2498</span>        return true;<a name="line.2498"></a>
-<span class="sourceLineNo">2499</span>      }<a name="line.2499"></a>
-<span class="sourceLineNo">2500</span>    }<a name="line.2500"></a>
-<span class="sourceLineNo">2501</span>    return false;<a name="line.2501"></a>
-<span class="sourceLineNo">2502</span>  }<a name="line.2502"></a>
-<span class="sourceLineNo">2503</span><a name="line.2503"></a>
-<span class="sourceLineNo">2504</span>  /**<a name="line.2504"></a>
-<span class="sourceLineNo">2505</span>   * Flushing all stores.<a name="line.2505"></a>
-<span class="sourceLineNo">2506</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2506"></a>
-<span class="sourceLineNo">2507</span>   */<a name="line.2507"></a>
-<span class="sourceLineNo">2508</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2508"></a>
-<span class="sourceLineNo">2509</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2509"></a>
-<span class="sourceLineNo">2510</span>  }<a name="line.2510"></a>
-<span class="sourceLineNo">2511</span><a name="line.2511"></a>
-<span class="sourceLineNo">2512</span>  /**<a name="line.2512"></a>
-<span class="sourceLineNo">2513</span>   * Flushing given stores.<a name="line.2513"></a>
-<span class="sourceLineNo">2514</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2514"></a>
-<span class="sourceLineNo">2515</span>   */<a name="line.2515"></a>
-<span class="sourceLineNo">2516</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2516"></a>
-<span class="sourceLineNo">2517</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2517"></a>
-<span class="sourceLineNo">2518</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2518"></a>
-<span class="sourceLineNo">2519</span>      writeFlushWalMarker, tracker);<a name="line.2519"></a>
-<span class="sourceLineNo">2520</span>  }<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span><a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>  /**<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>   * flush operation.<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>   * &lt;p&gt;<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2531"></a>
-<span class="sourceLineNo">2532</span>   * of this flush, etc.<a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>   * @param storesToFlush The list of stores to flush.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>   * @return object describing the flush's state<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>   * @throws IOException general io exceptions<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>   */<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>    PrepareFlushResult result =<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>    if (result.result == null) {<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>    } else {<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>    }<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>  }<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span><a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>      justification="FindBugs seems confused about trxId")<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>      // Don't flush when server aborting, it's unsafe<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>    }<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>    // to go get one.<a name="line.2566"></a>
-<span class="sourceLineNo">2567</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span>      this.updatesLock.writeLock().lock();<a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>      WriteEntry writeEntry = null;<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>      try {<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>          // (useful as marker when bulk loading, etc.).<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>          if (wal != null) {<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            writeEntry = mvcc.begin();<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>            FlushResultImpl flushResult =<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>            mvcc.completeAndWait(writeEntry);<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>            writeEntry = null;<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span>          } else {<a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>          }<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>        }<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>      } finally {<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>        if (writeEntry != null) {<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>          mvcc.complete(writeEntry);<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span>        }<a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>        this.updatesLock.writeLock().unlock();<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>      }<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>    }<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>    // during flush<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span>    // block waiting for the lock for internal flush<a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>    this.updatesLock.writeLock().lock();<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span><a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>    for (HStore store : storesToFlush) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>        store.preFlushSeqIDEstimation());<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>    }<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span><a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>    // will be in advance of this sequence id.<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>    try {<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span>      if (wal != null) {<a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2636"></a>
-<span class="sourceLineNo">2637</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>          status.setStatus(msg);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>          return new PrepareFlushResult(<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>              myseqid);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>        }<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>        flushedSeqId =<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>      } else {<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>      }<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>      for (HStore s : storesToFlush) {<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2656"></a>
-<span class="sourceLineNo">2657</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>        // for writing stores to WAL<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>      }<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span><a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>      // write the snapshot start to WAL<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>            mvcc);<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>      }<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>      // Prepare flush (take a snapshot)<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>      });<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>    } catch (IOException ex) {<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>      throw ex;<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>    } finally {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>      this.updatesLock.writeLock().unlock();<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>    }<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>    status.setStatus(s);<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>  }<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span><a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>  /**<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>   */<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>    if (!LOG.isInfoEnabled()) {<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span>      return;<a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>    }<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>    // Log a fat line detailing what is being flushed.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>    StringBuilder perCfExtras = null;<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>      perCfExtras = new StringBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>      for (HStore store: storesToFlush) {<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>        perCfExtras.append("={dataSize=")<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>        perCfExtras.append(", heapSize=")<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span>        perCfExtras.append(", offHeapSize=")<a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>        perCfExtras.append("}");<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>      }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>    }<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>  }<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span><a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>    if (wal == null) return;<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>    try {<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span>          mvcc);<a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>    } catch (Throwable t) {<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          StringUtils.stringifyException(t));<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>    }<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>  }<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span><a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>  /**<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>   */<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>  throws IOException {<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>    if (wal == null) {<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>      return;<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>    }<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>    try {<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>    } catch (IOException ioe) {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>      throw ioe;<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>    }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>  }<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span><a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>  /**<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>   * @return True if passed Set is all families in the region.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>   */<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>    return families == null || this.stores.size() == families.size();<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>  }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span><a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>  /**<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>   * @param wal<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>   * @return whether WAL write was successful<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>   */<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>      try {<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>            mvcc);<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>        return true;<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>      } catch (IOException e) {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>      }<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>    }<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>    return false;<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>  }<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span><a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>      justification="Intentional; notify is about completed flush")<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2788"></a>
-<span class="sourceLineNo">2789</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>    long startTime = prepareResult.startTime;<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span><a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>    String s = "Flushing stores of " + this;<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>    status.setStatus(s);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span><a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>    // be part of the current running servers state.<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>    boolean compactionRequested = false;<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>    long flushedOutputFileSize = 0;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>    try {<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>      // A.  Flush memstore to all the HStores.<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>      // Keep running vector of all store files that includes both old and the<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>      // tmp directory.<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span><a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>        flush.flushCache(status);<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      }<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span><a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>      // all the store scanners to reset/reseek).<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span>        boolean needsCompaction = flush.commit(status);<a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>        if (needsCompaction) {<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>          compactionRequested = true;<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>        }<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>        }<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>      }<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      storeFlushCtxs.clear();<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span><a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>      // Set down the memstore size by amount of flush.<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>      this.decrMemStoreSize(mss);<a name="line.2838"></a>
-<span class="sourceLineNo">2839</span><a name="line.2839"></a>
-<span class="sourceLineNo">2840</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2840"></a>
-<span class="sourceLineNo">2841</span>      // During startup, quota manager may not be initialized yet.<a name="line.2841"></a>
-<span class="sourceLineNo">2842</span>      if (rsServices != null) {<a name="line.2842"></a>
-<span class="sourceLineNo">2843</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2843"></a>
-<span class="sourceLineNo">2844</span>        if (quotaManager != null) {<a name="line.2844"></a>
-<span class="sourceLineNo">2845</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2845"></a>
-<span class="sourceLineNo">2846</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2846"></a>
-<span class="sourceLineNo">2847</span>        }<a name="line.2847"></a>
-<span class="sourceLineNo">2848</span>      }<a name="line.2848"></a>
-<span class="sourceLineNo">2849</span><a name="line.2849"></a>
-<span class="sourceLineNo">2850</span>      if (wal != null) {<a name="line.2850"></a>
-<span class="sourceLineNo">2851</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2851"></a>
-<span class="sourceLineNo">2852</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2852"></a>
-<span class="sourceLineNo">2853</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2853"></a>
-<span class="sourceLineNo">2854</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2854"></a>
-<span class="sourceLineNo">2855</span>            mvcc);<a name="line.2855"></a>
-<span class="sourceLineNo">2856</span>      }<a name="line.2856"></a>
-<span class="sourceLineNo">2857</span>    } catch (Throwable t) {<a name="line.2857"></a>
-<span class="sourceLineNo">2858</span>      // An exception here means that the snapshot was not persisted.<a name="line.2858"></a>
-<span class="sourceLineNo">2859</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2859"></a>
-<span class="sourceLineNo">2860</span>      // Currently, only a server restart will do this.<a name="line.2860"></a>
-<span class="sourceLineNo">2861</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2861"></a>
-<span class="sourceLineNo">2862</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2862"></a>
-<span class="sourceLineNo">2863</span>      // all and sundry.<a name="line.2863"></a>
-<span class="sourceLineNo">2864</span>      if (wal != null) {<a name="line.2864"></a>
-<span class="sourceLineNo">2865</span>        try {<a name="line.2865"></a>
-<span class="sourceLineNo">2866</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2866"></a>
-<span class="sourceLineNo">2867</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2867"></a>
-<span class="sourceLineNo">2868</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2868"></a>
-<span class="sourceLineNo">2869</span>        } catch (Throwable ex) {<a name="line.2869"></a>
-<span class="sourceLineNo">2870</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2870"></a>
-<span class="sourceLineNo">2871</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2871"></a>
-<span class="sourceLineNo">2872</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2872"></a>
-<span class="sourceLineNo">2873</span>        }<a name="line.2873"></a>
-<span class="sourceLineNo">2874</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2874"></a>
-<span class="sourceLineNo">2875</span>      }<a name="line.2875"></a>
-<span class="sourceLineNo">2876</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2876"></a>
-<span class="sourceLineNo">2877</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2877"></a>
-<span class="sourceLineNo">2878</span>      dse.initCause(t);<a name="line.2878"></a>
-<span class="sourceLineNo">2879</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2879"></a>
-<span class="sourceLineNo">2880</span><a name="line.2880"></a>
-<span class="sourceLineNo">2881</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2881"></a>
-<span class="sourceLineNo">2882</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2882"></a>
-<span class="sourceLineNo">2883</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2883"></a>
-<span class="sourceLineNo">2884</span>      // operations except for close will be rejected.<a name="line.2884"></a>
-<span class="sourceLineNo">2885</span>      this.closing.set(true);<a name="line.2885"></a>
-<span class="sourceLineNo">2886</span><a name="line.2886"></a>
-<span class="sourceLineNo">2887</span>      if (rsServices != null) {<a name="line.2887"></a>
-<span class="sourceLineNo">2888</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2888"></a>
-<span class="sourceLineNo">2889</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2889"></a>
-<span class="sourceLineNo">2890</span>      }<a name="line.2890"></a>
-<span class="sourceLineNo">2891</span><a name="line.2891"></a>
-<span class="sourceLineNo">2892</span>      throw dse;<a name="line.2892"></a>
-<span class="sourceLineNo">2893</span>    }<a name="line.2893"></a>
+<span class="sourceLineNo">2487</span>    if (modifiedFlushCheckInterval &lt;= 0) { //disabled<a name="line.2487"></a>
+<span class="sourceLineNo">2488</span>      return false;<a name="line.2488"></a>
+<span class="sourceLineNo">2489</span>    }<a name="line.2489"></a>
+<span class="sourceLineNo">2490</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.2490"></a>
+<span class="sourceLineNo">2491</span>    //if we flushed in the recent past, we don't need to do again now<a name="line.2491"></a>
+<span class="sourceLineNo">2492</span>    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {<a name="line.2492"></a>
+<span class="sourceLineNo">2493</span>      return false;<a name="line.2493"></a>
+<span class="sourceLineNo">2494</span>    }<a name="line.2494"></a>
+<span class="sourceLineNo">2495</span>    //since we didn't flush in the recent past, flush now if certain conditions<a name="line.2495"></a>
+<span class="sourceLineNo">2496</span>    //are met. Return true on first such memstore hit.<a name="line.2496"></a>
+<span class="sourceLineNo">2497</span>    for (HStore s : stores.values()) {<a name="line.2497"></a>
+<span class="sourceLineNo">2498</span>      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {<a name="line.2498"></a>
+<span class="sourceLineNo">2499</span>        // we have an old enough edit in the memstore, flush<a name="line.2499"></a>
+<span class="sourceLineNo">2500</span>        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");<a name="line.2500"></a>
+<span class="sourceLineNo">2501</span>        return true;<a name="line.2501"></a>
+<span class="sourceLineNo">2502</span>      }<a name="line.2502"></a>
+<span class="sourceLineNo">2503</span>    }<a name="line.2503"></a>
+<span class="sourceLineNo">2504</span>    return false;<a name="line.2504"></a>
+<span class="sourceLineNo">2505</span>  }<a name="line.2505"></a>
+<span class="sourceLineNo">2506</span><a name="line.2506"></a>
+<span class="sourceLineNo">2507</span>  /**<a name="line.2507"></a>
+<span class="sourceLineNo">2508</span>   * Flushing all stores.<a name="line.2508"></a>
+<span class="sourceLineNo">2509</span>   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2509"></a>
+<span class="sourceLineNo">2510</span>   */<a name="line.2510"></a>
+<span class="sourceLineNo">2511</span>  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {<a name="line.2511"></a>
+<span class="sourceLineNo">2512</span>    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.2512"></a>
+<span class="sourceLineNo">2513</span>  }<a name="line.2513"></a>
+<span class="sourceLineNo">2514</span><a name="line.2514"></a>
+<span class="sourceLineNo">2515</span>  /**<a name="line.2515"></a>
+<span class="sourceLineNo">2516</span>   * Flushing given stores.<a name="line.2516"></a>
+<span class="sourceLineNo">2517</span>   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)<a name="line.2517"></a>
+<span class="sourceLineNo">2518</span>   */<a name="line.2518"></a>
+<span class="sourceLineNo">2519</span>  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,<a name="line.2519"></a>
+<span class="sourceLineNo">2520</span>      boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {<a name="line.2520"></a>
+<span class="sourceLineNo">2521</span>    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>      writeFlushWalMarker, tracker);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>  }<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span><a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>  /**<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>   * memstore, all of which have also been written to the wal. We need to write those updates in the<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>   * memstore out to disk, while being able to process reads/writes as much as possible during the<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>   * flush operation.<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>   * &lt;p&gt;<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>   * This method may block for some time. Every time you call it, we up the regions sequence id even<a name="line.2531"></a>
+<span class="sourceLineNo">2532</span>   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit<a name="line.2532"></a>
+<span class="sourceLineNo">2533</span>   * applied to this region. The returned id does not refer to an actual edit. The returned id can<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span>   * of this flush, etc.<a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>   * @param wal Null if we're NOT to go via wal.<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>   * @param myseqid The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>   * @param storesToFlush The list of stores to flush.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>   * @return object describing the flush's state<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>   * @throws IOException general io exceptions<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>   * @throws DroppedSnapshotException Thrown when replay of WAL is required.<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>   */<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>    PrepareFlushResult result =<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>        internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>    if (result.result == null) {<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>    } else {<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>      return result.result; // early exit due to failure from prepare stage<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>    }<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>  }<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span><a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DLS_DEAD_LOCAL_STORE",<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>      justification="FindBugs seems confused about trxId")<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span>  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,<a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>      Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>      FlushLifeCycleTracker tracker) throws IOException {<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>      // Don't flush when server aborting, it's unsafe<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>      throw new IOException("Aborting flush because server is aborted...");<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>    }<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>    final long startTime = EnvironmentEdgeManager.currentTime();<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>    // If nothing to flush, return, but return with a valid unused sequenceId.<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a<a name="line.2566"></a>
+<span class="sourceLineNo">2567</span>    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs<a name="line.2567"></a>
+<span class="sourceLineNo">2568</span>    // to no other that it can use to associate with the bulk load. Hence this little dance below<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>    // to go get one.<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>    if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>      // Take an update lock so no edits can come into memory just yet.<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span>      this.updatesLock.writeLock().lock();<a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>      WriteEntry writeEntry = null;<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>      try {<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>        if (this.memStoreSizing.getDataSize() &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>          // Presume that if there are still no edits in the memstore, then there are no edits for<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>          // this region out in the WAL subsystem so no need to do any trickery clearing out<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>          // sure just beyond the last appended region edit and not associated with any edit<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>          // (useful as marker when bulk loading, etc.).<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>          if (wal != null) {<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            writeEntry = mvcc.begin();<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            long flushOpSeqId = writeEntry.getWriteNumber();<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>            FlushResultImpl flushResult =<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>                new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId,<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                    "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker));<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>            mvcc.completeAndWait(writeEntry);<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>            // Set to null so we don't complete it again down in finally block.<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>            writeEntry = null;<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>            return new PrepareFlushResult(flushResult, myseqid);<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span>          } else {<a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>            return new PrepareFlushResult(new FlushResultImpl(<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>          }<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>        }<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>      } finally {<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>        if (writeEntry != null) {<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>          // but complete it anyways so it doesn't block the mvcc queue.<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>          mvcc.complete(writeEntry);<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span>        }<a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>        this.updatesLock.writeLock().unlock();<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>      }<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>    }<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>    logFatLineOnFlush(storesToFlush, myseqid);<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>    // to do this for a moment.  It is quick. We also set the memstore size to zero here before we<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>    // allow updates again so its value will represent the size of the updates received<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>    // during flush<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>    // We have to take an update lock during snapshot, or else a write could end up in both snapshot<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>    // and memstore (makes it difficult to do atomic rows then)<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>    status.setStatus("Obtaining lock to block concurrent updates");<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span>    // block waiting for the lock for internal flush<a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>    this.updatesLock.writeLock().lock();<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span><a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>    for (HStore store : storesToFlush) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>        store.preFlushSeqIDEstimation());<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>    }<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span><a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>    // The sequence id of this flush operation which is used to log FlushMarker and pass to<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>    // createFlushContext to use as the store file's sequence id. It can be in advance of edits<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>    // still in the memstore, edits that are in other column families yet to be flushed.<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>    long flushOpSeqId = HConstants.NO_SEQNUM;<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span>    // The max flushed sequence id after this flush operation completes. All edits in memstore<a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>    // will be in advance of this sequence id.<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>    long flushedSeqId = HConstants.NO_SEQNUM;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>    try {<a name="line.2636"></a>
+<span class="sourceLineNo">2637</span>      if (wal != null) {<a name="line.2637"></a>
+<span class="sourceLineNo">2638</span>        Long earliestUnflushedSequenceIdForTheRegion =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>            wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span>        if (earliestUnflushedSequenceIdForTheRegion == null) {<a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>          // This should never happen. This is how startCacheFlush signals flush cannot proceed.<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>          status.setStatus(msg);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>          return new PrepareFlushResult(<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>              new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false),<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>              myseqid);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>        }<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>        flushOpSeqId = getNextSequenceId(wal);<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>        flushedSeqId =<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>            earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM?<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                flushOpSeqId: earliestUnflushedSequenceIdForTheRegion.longValue() - 1;<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>      } else {<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>        // use the provided sequence Id as WAL is not being used for this flush.<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>        flushedSeqId = flushOpSeqId = myseqid;<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>      }<a name="line.2656"></a>
+<span class="sourceLineNo">2657</span><a name="line.2657"></a>
+<span class="sourceLineNo">2658</span>      for (HStore s : storesToFlush) {<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span>          s.createFlushContext(flushOpSeqId, tracker));<a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>        // for writing stores to WAL<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>      }<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span><a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>      // write the snapshot start to WAL<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>      if (wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>            mvcc);<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>      }<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>      // Prepare flush (take a snapshot)<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>      storeFlushCtxs.forEach((name, flush) -&gt; {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>        MemStoreSize snapshotSize = flush.prepare();<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>        storeFlushableSize.put(name, snapshotSize);<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>      });<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>    } catch (IOException ex) {<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>      throw ex;<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>    } finally {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>      this.updatesLock.writeLock().unlock();<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>    }<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, " +<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>        "flushsize=" + totalSizeOfFlushableStores;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>    status.setStatus(s);<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>    doSyncOfUnflushedWALChanges(wal, getRegionInfo());<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span>        flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);<a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>  }<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span><a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>  /**<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>   * Utility method broken out of internalPrepareFlushCache so that method is smaller.<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>   */<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>    if (!LOG.isInfoEnabled()) {<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span>      return;<a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>    }<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>    // Log a fat line detailing what is being flushed.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>    StringBuilder perCfExtras = null;<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>    if (!isAllFamilies(storesToFlush)) {<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>      perCfExtras = new StringBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>      for (HStore store: storesToFlush) {<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span>        MemStoreSize mss = store.getFlushableSize();<a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>        perCfExtras.append("; ").append(store.getColumnFamilyName());<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>        perCfExtras.append("={dataSize=")<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>            .append(StringUtils.byteDesc(mss.getDataSize()));<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>        perCfExtras.append(", heapSize=")<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>            .append(StringUtils.byteDesc(mss.getHeapSize()));<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span>        perCfExtras.append(", offHeapSize=")<a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>            .append(StringUtils.byteDesc(mss.getOffHeapSize()));<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>        perCfExtras.append("}");<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>      }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>    }<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>    LOG.info("Flushing " + storesToFlush.size() + "/" + stores.size() + " column families," +<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>        " dataSize=" + StringUtils.byteDesc(mss.getDataSize()) +<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>        " heapSize=" + StringUtils.byteDesc(mss.getHeapSize()) +<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>        ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0)? perCfExtras.toString(): "") +<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>        ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>  }<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span><a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>      final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>    if (wal == null) return;<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>    try {<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span>          mvcc);<a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>    } catch (Throwable t) {<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL:" +<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          StringUtils.stringifyException(t));<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>      // ignore this since we will be aborting the RS with DSE.<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>    }<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>    // we have called wal.startCacheFlush(), now we have to abort it<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>  }<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span><a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>  /**<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>   * Sync unflushed WAL changes. See HBASE-8208 for details<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>   */<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>  throws IOException {<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>    if (wal == null) {<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>      return;<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>    }<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>    try {<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>      wal.sync(); // ensure that flush marker is sync'ed<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>    } catch (IOException ioe) {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>      wal.abortCacheFlush(hri.getEncodedNameAsBytes());<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>      throw ioe;<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>    }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>  }<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span><a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>  /**<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>   * @return True if passed Set is all families in the region.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>   */<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>    return families == null || this.stores.size() == families.size();<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>  }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span><a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>  /**<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span>   * Writes a marker to WAL indicating a flush is requested but cannot be complete due to various<a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>   * reasons. Ignores exceptions from WAL. Returns whether the write succeeded.<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>   * @param wal<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>   * @return whether WAL write was successful<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>   */<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>  private boolean writeFlushRequestMarkerToWAL(WAL wal, boolean writeFlushWalMarker) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH,<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        getRegionInfo(), -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>      try {<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>            mvcc);<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>        return true;<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>      } catch (IOException e) {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>            + "Received exception while trying to write the flush request to wal", e);<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>      }<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>    }<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>    return false;<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>  }<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span><a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>      justification="Intentional; notify is about completed flush")<a name="line.2788"></a>
+<span class="sourceLineNo">2789</span>  protected FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,<a name="line.2789"></a>
+<span class="sourceLineNo">2790</span>      PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>    // prepare flush context is carried via PrepareFlushResult<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>    long startTime = prepareResult.startTime;<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span>    long flushOpSeqId = prepareResult.flushOpSeqId;<a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>    long flushedSeqId = prepareResult.flushedSeqId;<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span><a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>    String s = "Flushing stores of " + this;<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>    status.setStatus(s);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>    if (LOG.isTraceEnabled()) LOG.trace(s);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span><a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    // Any failure from here on out will be catastrophic requiring server<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>    // restart so wal content can be replayed and put back into the memstore.<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>    // Otherwise, the snapshot content while backed up in the wal, it will not<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>    // be part of the current running servers state.<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>    boolean compactionRequested = false;<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>    long flushedOutputFileSize = 0;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>    try {<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>      // A.  Flush memstore to all the HStores.<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>      // Keep running vector of all store files that includes both old and the<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>      // just-made new flush store file. The new flushed file is still in the<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>      // tmp directory.<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span><a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>        flush.flushCache(status);<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      }<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span><a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      // Switch snapshot (in memstore) -&gt; new hfile (thus causing<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>      // all the store scanners to reset/reseek).<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      Iterator&lt;HStore&gt; it = storesToFlush.iterator();<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>      // stores.values() and storeFlushCtxs have same order<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>      for (StoreFlushContext flush : storeFlushCtxs.values()) {<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span>        boolean needsCompaction = flush.commit(status);<a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>        if (needsCompaction) {<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>          compactionRequested = true;<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>        }<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>        byte[] storeName = it.next().getColumnFamilyDescriptor().getName();<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>        List&lt;Path&gt; storeCommittedFiles = flush.getCommittedFiles();<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span>        committedFiles.put(storeName, storeCommittedFiles);<a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>        // Flush committed no files, indicating flush is empty or flush was canceled<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>        }<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>        flushedOutputFileSize += flush.getOutputFileSize();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>      }<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      storeFlushCtxs.clear();<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span><a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>      // Set down the memstore size by amount of flush.<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>      this.decrMemStoreSize(mss);<a name="line.2841"></a>
+<span class="sourceLineNo">2842</span><a name="line.2842"></a>
+<span class="sourceLineNo">2843</span>      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.<a name="line.2843"></a>
+<span class="sourceLineNo">2844</span>      // During startup, quota manager may not be initialized yet.<a name="line.2844"></a>
+<span class="sourceLineNo">2845</span>      if (rsServices != null) {<a name="line.2845"></a>
+<span class="sourceLineNo">2846</span>        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();<a name="line.2846"></a>
+<span class="sourceLineNo">2847</span>        if (quotaManager != null) {<a name="line.2847"></a>
+<span class="sourceLineNo">2848</span>          quotaManager.getRegionSizeStore().incrementRegionSize(<a name="line.2848"></a>
+<span class="sourceLineNo">2849</span>              this.getRegionInfo(), flushedOutputFileSize);<a name="line.2849"></a>
+<span class="sourceLineNo">2850</span>        }<a name="line.2850"></a>
+<span class="sourceLineNo">2851</span>      }<a name="line.2851"></a>
+<span class="sourceLineNo">2852</span><a name="line.2852"></a>
+<span class="sourceLineNo">2853</span>      if (wal != null) {<a name="line.2853"></a>
+<span class="sourceLineNo">2854</span>        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException<a name="line.2854"></a>
+<span class="sourceLineNo">2855</span>        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,<a name="line.2855"></a>
+<span class="sourceLineNo">2856</span>          getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2856"></a>
+<span class="sourceLineNo">2857</span>        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true,<a name="line.2857"></a>
+<span class="sourceLineNo">2858</span>            mvcc);<a name="line.2858"></a>
+<span class="sourceLineNo">2859</span>      }<a name="line.2859"></a>
+<span class="sourceLineNo">2860</span>    } catch (Throwable t) {<a name="line.2860"></a>
+<span class="sourceLineNo">2861</span>      // An exception here means that the snapshot was not persisted.<a name="line.2861"></a>
+<span class="sourceLineNo">2862</span>      // The wal needs to be replayed so its content is restored to memstore.<a name="line.2862"></a>
+<span class="sourceLineNo">2863</span>      // Currently, only a server restart will do this.<a name="line.2863"></a>
+<span class="sourceLineNo">2864</span>      // We used to only catch IOEs but its possible that we'd get other<a name="line.2864"></a>
+<span class="sourceLineNo">2865</span>      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch<a name="line.2865"></a>
+<span class="sourceLineNo">2866</span>      // all and sundry.<a name="line.2866"></a>
+<span class="sourceLineNo">2867</span>      if (wal != null) {<a name="line.2867"></a>
+<span class="sourceLineNo">2868</span>        try {<a name="line.2868"></a>
+<span class="sourceLineNo">2869</span>          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,<a name="line.2869"></a>
+<span class="sourceLineNo">2870</span>            getRegionInfo(), flushOpSeqId, committedFiles);<a name="line.2870"></a>
+<span class="sourceLineNo">2871</span>          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc);<a name="line.2871"></a>
+<span class="sourceLineNo">2872</span>        } catch (Throwable ex) {<a name="line.2872"></a>
+<span class="sourceLineNo">2873</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.2873"></a>
+<span class="sourceLineNo">2874</span>              + "failed writing ABORT_FLUSH marker to WAL", ex);<a name="line.2874"></a>
+<span class="sourceLineNo">2875</span>          // ignore this since we will be aborting the RS with DSE.<a name="line.2875"></a>
+<span class="sourceLineNo">2876</span>        }<a name="line.2876"></a>
+<span class="sourceLineNo">2877</span>        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2877"></a>
+<span class="sourceLineNo">2878</span>      }<a name="line.2878"></a>
+<span class="sourceLineNo">2879</span>      DroppedSnapshotException dse = new DroppedSnapshotException("region: " +<a name="line.2879"></a>
+<span class="sourceLineNo">2880</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.2880"></a>
+<span class="sourceLineNo">2881</span>      dse.initCause(t);<a name="line.2881"></a>
+<span class="sourceLineNo">2882</span>      status.abort("Flush failed: " + StringUtils.stringifyException(t));<a name="line.2882"></a>
+<span class="sourceLineNo">2883</span><a name="line.2883"></a>
+<span class="sourceLineNo">2884</span>      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.<a name="line.2884"></a>
+<span class="sourceLineNo">2885</span>      // However, since we may have the region read lock, we cannot call close(true) here since<a name="line.2885"></a>
+<span class="sourceLineNo">2886</span>      // we cannot promote to a write lock. Instead we are setting closing so that all other region<a name="line.2886"></a>
+<span class="sourceLineNo">2887</span>      // operations except for close will be rejected.<a name="line.2887"></a>
+<span class="sourceLineNo">2888</span>      this.closing.set(true);<a name="line.2888"></a>
+<span class="sourceLineNo">2889</span><a name="line.2889"></a>
+<span class="sourceLineNo">2890</span>      if (rsServices != null) {<a name="line.2890"></a>
+<span class="sourceLineNo">2891</span>        // This is a safeguard against the case where the caller fails to explicitly handle aborting<a name="line.2891"></a>
+<span class="sourceLineNo">2892</span>        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);<a name="line.2892"></a>
+<span class="sourceLineNo">2893</span>      }<a name="line.2893"></a>
 <span class="sourceLineNo">2894</span><a name="line.2894"></a>
-<span class="sourceLineNo">2895</span>    // If we get to here, the HStores have been written.<a name="line.2895"></a>
-<span class="sourceLineNo">2896</span>    if (wal != null) {<a name="line.2896"></a>
-<span class="sourceLineNo">2897</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2897"></a>
-<span class="sourceLineNo">2898</span>    }<a name="line.2898"></a>
-<span class="sourceLineNo">2899</span><a name="line.2899"></a>
-<span class="sourceLineNo">2900</span>    // Record latest flush time<a name="line.2900"></a>
-<span class="sourceLineNo">2901</span>    for (HStore store: storesToFlush) {<a name="line.2901"></a>
-<span class="sourceLineNo">2902</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2902"></a>
-<span class="sourceLineNo">2903</span>    }<a name="line.2903"></a>
-<span class="sourceLineNo">2904</span><a name="line.2904"></a>
-<span class="sourceLineNo">2905</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2905"></a>
-<span class="sourceLineNo">2906</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2906"></a>
+<span class="sourceLineNo">2895</span>      throw dse;<a name="line.2895"></a>
+<span class="sourceLineNo">2896</span>    }<a name="line.2896"></a>
+<span class="sourceLineNo">2897</span><a name="line.2897"></a>
+<span class="sourceLineNo">2898</span>    // If we get to here, the HStores have been written.<a name="line.2898"></a>
+<span class="sourceLineNo">2899</span>    if (wal != null) {<a name="line.2899"></a>
+<span class="sourceLineNo">2900</span>      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());<a name="line.2900"></a>
+<span class="sourceLineNo">2901</span>    }<a name="line.2901"></a>
+<span class="sourceLineNo">2902</span><a name="line.2902"></a>
+<span class="sourceLineNo">2903</span>    // Record latest flush time<a name="line.2903"></a>
+<span class="sourceLineNo">2904</span>    for (HStore store: storesToFlush) {<a name="line.2904"></a>
+<span class="sourceLineNo">2905</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.2905"></a>
+<span class="sourceLineNo">2906</span>    }<a name="line.2906"></a>
 <span class="sourceLineNo">2907</span><a name="line.2907"></a>
-<span class="sourceLineNo">2908</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2908"></a>
-<span class="sourceLineNo">2909</span>    // e.g. checkResources().<a name="line.2909"></a>
-<span class="sourceLineNo">2910</span>    synchronized (this) {<a name="line.2910"></a>
-<span class="sourceLineNo">2911</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2911"></a>
-<span class="sourceLineNo">2912</span>    }<a name="line.2912"></a>
-<span class="sourceLineNo">2913</span><a name="line.2913"></a>
-<span class="sourceLineNo">2914</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2914"></a>
-<span class="sourceLineNo">2915</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2915"></a>
-<span class="sourceLineNo">2916</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2916"></a>
-<span class="sourceLineNo">2917</span>    String msg = "Finished flush of"<a name="line.2917"></a>
-<span class="sourceLineNo">2918</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2918"></a>
-<span class="sourceLineNo">2919</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2919"></a>
-<span class="sourceLineNo">2920</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2920"></a>
-<span class="sourceLineNo">2921</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2921"></a>
-<span class="sourceLineNo">2922</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2922"></a>
-<span class="sourceLineNo">2923</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2923"></a>
-<span class="sourceLineNo">2924</span>    LOG.info(msg);<a name="line.2924"></a>
-<span class="sourceLineNo">2925</span>    status.setStatus(msg);<a name="line.2925"></a>
-<span class="sourceLineNo">2926</span><a name="line.2926"></a>
-<span class="sourceLineNo">2927</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2927"></a>
-<span class="sourceLineNo">2928</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2928"></a>
-<span class="sourceLineNo">2929</span>          time,<a name="line.2929"></a>
-<span class="sourceLineNo">2930</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2930"></a>
-<span class="sourceLineNo">2931</span>    }<a name="line.2931"></a>
-<span class="sourceLineNo">2932</span><a name="line.2932"></a>
-<span class="sourceLineNo">2933</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2933"></a>
-<span class="sourceLineNo">2934</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2934"></a>
-<span class="sourceLineNo">2935</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2935"></a>
-<span class="sourceLineNo">2936</span>  }<a name="line.2936"></a>
-<span class="sourceLineNo">2937</span><a name="line.2937"></a>
-<span class="sourceLineNo">2938</span>  /**<a name="line.2938"></a>
-<span class="sourceLineNo">2939</span>   * Method to safely get the next sequence number.<a name="line.2939"></a>
-<span class="sourceLineNo">2940</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2940"></a>
-<span class="sourceLineNo">2941</span>   * @throws IOException<a name="line.2941"></a>
-<span class="sourceLineNo">2942</span>   */<a name="line.2942"></a>
-<span class="sourceLineNo">2943</span>  @VisibleForTesting<a name="line.2943"></a>
-<span class="sourceLineNo">2944</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2944"></a>
-<span class="sourceLineNo">2945</span>    WriteEntry we = mvcc.begin();<a name="line.2945"></a>
-<span class="sourceLineNo">2946</span>    mvcc.completeAndWait(we);<a name="line.2946"></a>
-<span class="sourceLineNo">2947</span>    return we.getWriteNumber();<a name="line.2947"></a>
-<span class="sourceLineNo">2948</span>  }<a name="line.2948"></a>
-<span class="sourceLineNo">2949</span><a name="line.2949"></a>
-<span class="sourceLineNo">2950</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2950"></a>
-<span class="sourceLineNo">2951</span>  // get() methods for client use.<a name="line.2951"></a>
-<span class="sourceLineNo">2952</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2952"></a>
-<span class="sourceLineNo">2953</span><a name="line.2953"></a>
-<span class="sourceLineNo">2954</span>  @Override<a name="line.2954"></a>
-<span class="sourceLineNo">2955</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2955"></a>
-<span class="sourceLineNo">2956</span>   return getScanner(scan, null);<a name="line.2956"></a>
-<span class="sourceLineNo">2957</span>  }<a name="line.2957"></a>
-<span class="sourceLineNo">2958</span><a name="line.2958"></a>
-<span class="sourceLineNo">2959</span>  @Override<a name="line.2959"></a>
-<span class="sourceLineNo">2960</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2960"></a>
-<span class="sourceLineNo">2961</span>      throws IOException {<a name="line.2961"></a>
-<span class="sourceLineNo">2962</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2962"></a>
-<span class="sourceLineNo">2963</span>  }<a name="line.2963"></a>
-<span class="sourceLineNo">2964</span><a name="line.2964"></a>
-<span class="sourceLineNo">2965</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2965"></a>
-<span class="sourceLineNo">2966</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2966"></a>
-<span class="sourceLineNo">2967</span>    startRegionOperation(Operation.SCAN);<a name="line.2967"></a>
-<span class="sourceLineNo">2968</span>    try {<a name="line.2968"></a>
-<span class="sourceLineNo">2969</span>      // Verify families are all valid<a name="line.2969"></a>
-<span class="sourceLineNo">2970</span>      if (!scan.hasFamilies()) {<a name="line.2970"></a>
-<span class="sourceLineNo">2971</span>        // Adding all families to scanner<a name="line.2971"></a>
-<span class="sourceLineNo">2972</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2972"></a>
-<span class="sourceLineNo">2973</span>          scan.addFamily(family);<a name="line.2973"></a>
-<span class="sourceLineNo">2974</span>        }<a name="line.2974"></a>
-<span class="sourceLineNo">2975</span>      } else {<a name="line.2975"></a>
-<span class="sourceLineNo">2976</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2976"></a>
-<span class="sourceLineNo">2977</span>          checkFamily(family);<a name="line.2977"></a>
-<span class="sourceLineNo">2978</span>        }<a name="line.2978"></a>
-<span class="sourceLineNo">2979</span>      }<a name="line.2979"></a>
-<span class="sourceLineNo">2980</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2980"></a>
-<span class="sourceLineNo">2981</span>    } finally {<a name="line.2981"></a>
-<span class="sourceLineNo">2982</span>      closeRegionOperation(Operation.SCAN);<a name="line.2982"></a>
-<span class="sourceLineNo">2983</span>    }<a name="line.2983"></a>
-<span class="sourceLineNo">2984</span>  }<a name="line.2984"></a>
-<span class="sourceLineNo">2985</span><a name="line.2985"></a>
-<span class="sourceLineNo">2986</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2986"></a>
-<span class="sourceLineNo">2987</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2987"></a>
-<span class="sourceLineNo">2988</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2988"></a>
-<span class="sourceLineNo">2989</span>      HConstants.NO_NONCE);<a name="line.2989"></a>
-<span class="sourceLineNo">2990</span>  }<a name="line.2990"></a>
-<span class="sourceLineNo">2991</span><a name="line.2991"></a>
-<span class="sourceLineNo">2992</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2992"></a>
-<span class="sourceLineNo">2993</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2993"></a>
-<span class="sourceLineNo">2994</span>    if (scan.isReversed()) {<a name="line.2994"></a>
-<span class="sourceLineNo">2995</span>      if (scan.getFilter() != null) {<a name="line.2995"></a>
-<span class="sourceLineNo">2996</span>        scan.getFilter().setReversed(true);<a name="line.2996"></a>
-<span class="sourceLineNo">2997</span>      }<a name="line.2997"></a>
-<span class="sourceLineNo">2998</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.2998"></a>
-<span class="sourceLineNo">2999</span>    }<a name="line.2999"></a>
-<span class="sourceLineNo">3000</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3000"></a>
-<span class="sourceLineNo">3001</span>  }<a name="line.3001"></a>
-<span class="sourceLineNo">3002</span><a name="line.3002"></a>
-<span class="sourceLineNo">3003</span>  /**<a name="line.3003"></a>
-<span class="sourceLineNo">3004</span>   * Prepare a delete for a row mutation processor<a name="line.3004"></a>
-<span class="sourceLineNo">3005</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3005"></a>
-<span class="sourceLineNo">3006</span>   * @throws IOException<a name="line.3006"></a>
-<span class="sourceLineNo">3007</span>   */<a name="line.3007"></a>
-<span class="sourceLineNo">3008</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3008"></a>
-<span class="sourceLineNo">3009</span>    // Check to see if this is a deleteRow insert<a name="line.3009"></a>
-<span class="sourceLineNo">3010</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3010"></a>
-<span class="sourceLineNo">3011</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3011"></a>
-<span class="sourceLineNo">3012</span>        // Don't eat the timestamp<a name="line.3012"></a>
-<span class="sourceLineNo">3013</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3013"></a>
-<span class="sourceLineNo">3014</span>      }<a name="line.3014"></a>
-<span class="sourceLineNo">3015</span>    } else {<a name="line.3015"></a>
-<span class="sourceLineNo">3016</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3016"></a>
-<span class="sourceLineNo">3017</span>        if(family == null) {<a name="line.3017"></a>
-<span class="sourceLineNo">3018</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3018"></a>
-<span class="sourceLineNo">3019</span>        }<a name="line.3019"></a>
-<span class="sourceLineNo">3020</span>        checkFamily(family, delete.getDurability());<a name="line.3020"></a>
-<span class="sourceLineNo">3021</span>      }<a name="line.3021"></a>
-<span class="sourceLineNo">3022</span>    }<a name="line.3022"></a>
-<span class="sourceLineNo">3023</span>  }<a name="line.3023"></a>
-<span class="sourceLineNo">3024</span><a name="line.3024"></a>
-<span class="sourceLineNo">3025</span>  @Override<a name="line.3025"></a>
-<span class="sourceLineNo">3026</span>  public void delete(Delete delete) throws IOException {<a name="line.3026"></a>
-<span class="sourceLineNo">3027</span>    checkReadOnly();<a name="line.3027"></a>
-<span class="sourceLineNo">3028</span>    checkResources();<a name="line.3028"></a>
-<span class="sourceLineNo">3029</span>    startRegionOperation(Operation.DELETE);<a name="line.3029"></a>
-<span class="sourceLineNo">3030</span>    try {<a name="line.3030"></a>
-<span class="sourceLineNo">3031</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3031"></a>
-<span class="sourceLineNo">3032</span>      doBatchMutate(delete);<a name="line.3032"></a>
-<span class="sourceLineNo">3033</span>    } finally {<a name="line.3033"></a>
-<span class="sourceLineNo">3034</span>      closeRegionOperation(Operation.DELETE);<a name="line.3034"></a>
-<span class="sourceLineNo">3035</span>    }<a name="line.3035"></a>
-<span class="sourceLineNo">3036</span>  }<a name="line.3036"></a>
-<span class="sourceLineNo">3037</span><a name="line.3037"></a>
-<span class="sourceLineNo">3038</span>  /**<a name="line.3038"></a>
-<span class="sourceLineNo">3039</span>   * Row needed by below method.<a name="line.3039"></a>
-<span class="sourceLineNo">3040</span>   */<a name="line.3040"></a>
-<span class="sourceLineNo">3041</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3041"></a>
-<span class="sourceLineNo">3042</span><a name="line.3042"></a>
-<span class="sourceLineNo">3043</span>  /**<a name="line.3043"></a>
-<span class="sourceLineNo">3044</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3044"></a>
-<span class="sourceLineNo">3045</span>   * @param familyMap map of family to edits for the given family.<a name="line.3045"></a>
-<span class="sourceLineNo">3046</span>   * @throws IOException<a name="line.3046"></a>
-<span class="sourceLineNo">3047</span>   */<a name="line.3047"></a>
-<span class="sourceLineNo">3048</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3048"></a>
-<span class="sourceLineNo">3049</span>      Durability durability) throws IOException {<a name="line.3049"></a>
-<span class="sourceLineNo">3050</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3050"></a>
-<span class="sourceLineNo">3051</span>    delete.setDurability(durability);<a name="line.3051"></a>
-<span class="sourceLineNo">3052</span>    doBatchMutate(delete);<a name="line.3052"></a>
-<span class="sourceLineNo">3053</span>  }<a name="line.3053"></a>
-<span class="sourceLineNo">3054</span><a name="line.3054"></a>
-<span class="sourceLineNo">3055</span>  /**<a name="line.3055"></a>
-<span class="sourceLineNo">3056</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3056"></a>
-<span class="sourceLineNo">3057</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3057"></a>
-<span class="sourceLineNo">3058</span>   * @param mutation<a name="line.3058"></a>
-<span class="sourceLineNo">3059</span>   * @param familyMap<a name="line.3059"></a>
-<span class="sourceLineNo">3060</span>   * @param byteNow<a name="line.3060"></a>
-<span class="sourceLineNo">3061</span>   * @throws IOException<a name="line.3061"></a>
-<span class="sourceLineNo">3062</span>   */<a name="line.3062"></a>
-<span class="sourceLineNo">3063</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3063"></a>
-<span class="sourceLineNo">3064</span>      byte[] byteNow) throws IOException {<a name="line.3064"></a>
-<span class="sourceLineNo">3065</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3065"></a>
-<span class="sourceLineNo">3066</span><a name="line.3066"></a>
-<span class="sourceLineNo">3067</span>      byte[] family = e.getKey();<a name="line.3067"></a>
-<span class="sourceLineNo">3068</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3068"></a>
-<span class="sourceLineNo">3069</span>      assert cells instanceof RandomAccess;<a name="line.3069"></a>
-<span class="sourceLineNo">3070</span><a name="line.3070"></a>
-<span class="sourceLineNo">3071</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3071"></a>
-<span class="sourceLineNo">3072</span>      int listSize = cells.size();<a name="line.3072"></a>
-<span class="sourceLineNo">3073</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3073"></a>
-<span class="sourceLineNo">3074</span>        Cell cell = cells.get(i);<a name="line.3074"></a>
-<span class="sourceLineNo">3075</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3075"></a>
-<span class="sourceLineNo">3076</span>        //  This is expensive.<a name="line.3076"></a>
-<span class="sourceLineNo">3077</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3077"></a>
-<span class="sourceLineNo">3078</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3078"></a>
-<span class="sourceLineNo">3079</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3079"></a>
-<span class="sourceLineNo">3080</span><a name="line.3080"></a>
-<span class="sourceLineNo">3081</span>          Integer count = kvCount.get(qual);<a name="line.3081"></a>
-<span class="sourceLineNo">3082</span>          if (count == null) {<a name="line.3082"></a>
-<span class="sourceLineNo">3083</span>            kvCount.put(qual, 1);<a name="line.3083"></a>
-<span class="sourceLineNo">3084</span>          } else {<a name="line.3084"></a>
-<span class="sourceLineNo">3085</span>            kvCount.put(qual, count + 1);<a name="line.3085"></a>
-<span class="sourceLineNo">3086</span>          }<a name="line.3086"></a>
-<span class="sourceLineNo">3087</span>          count = kvCount.get(qual);<a name="line.3087"></a>
-<span class="sourceLineNo">3088</span><a name="line.3088"></a>
-<span class="sourceLineNo">3089</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3089"></a>
-<span class="sourceLineNo">3090</span>          get.readVersions(count);<a name="line.3090"></a>
-<span class="sourceLineNo">3091</span>          get.addColumn(family, qual);<a name="line.3091"></a>
-<span class="sourceLineNo">3092</span>          if (coprocessorHost != null) {<a name="line.3092"></a>
-<span class="sourceLineNo">3093</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3093"></a>
-<span class="sourceLineNo">3094</span>                byteNow, get)) {<a name="line.3094"></a>
-<span class="sourceLineNo">3095</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3095"></a>
-<span class="sourceLineNo">3096</span>            }<a name="line.3096"></a>
-<span class="sourceLineNo">3097</span>          } else {<a name="line.3097"></a>
-<span class="sourceLineNo">3098</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
-<span class="sourceLineNo">3099</span>          }<a name="line.3099"></a>
-<span class="sourceLineNo">3100</span>        } else {<a name="line.3100"></a>
-<span class="sourceLineNo">3101</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3101"></a>
-<span class="sourceLineNo">3102</span>        }<a name="line.3102"></a>
-<span class="sourceLineNo">3103</span>      }<a name="line.3103"></a>
-<span class="sourceLineNo">3104</span>    }<a name="line.3104"></a>
-<span class="sourceLineNo">3105</span>  }<a name="line.3105"></a>
-<span class="sourceLineNo">3106</span><a name="line.3106"></a>
-<span class="sourceLineNo">3107</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3107"></a>
-<span class="sourceLineNo">3108</span>      throws IOException {<a name="line.3108"></a>
-<span class="sourceLineNo">3109</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3109"></a>
-<span class="sourceLineNo">3110</span><a name="line.3110"></a>
-<span class="sourceLineNo">3111</span>    if (result.size() &lt; count) {<a name="line.3111"></a>
-<span class="sourceLineNo">3112</span>      // Nothing to delete<a name="line.3112"></a>
-<span class="sourceLineNo">3113</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3113"></a>
-<span class="sourceLineNo">3114</span>      return;<a name="line.3114"></a>
-<span class="sourceLineNo">3115</span>    }<a name="line.3115"></a>
-<span class="sourceLineNo">3116</span>    if (result.size() &gt; count) {<a name="line.3116"></a>
-<span class="sourceLineNo">3117</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3117"></a>
+<span class="sourceLineNo">2908</span>    this.maxFlushedSeqId = flushedSeqId;<a name="line.2908"></a>
+<span class="sourceLineNo">2909</span>    this.lastFlushOpSeqId = flushOpSeqId;<a name="line.2909"></a>
+<span class="sourceLineNo">2910</span><a name="line.2910"></a>
+<span class="sourceLineNo">2911</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.2911"></a>
+<span class="sourceLineNo">2912</span>    // e.g. checkResources().<a name="line.2912"></a>
+<span class="sourceLineNo">2913</span>    synchronized (this) {<a name="line.2913"></a>
+<span class="sourceLineNo">2914</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.2914"></a>
+<span class="sourceLineNo">2915</span>    }<a name="line.2915"></a>
+<span class="sourceLineNo">2916</span><a name="line.2916"></a>
+<span class="sourceLineNo">2917</span>    long time = EnvironmentEdgeManager.currentTime() - startTime;<a name="line.2917"></a>
+<span class="sourceLineNo">2918</span>    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();<a name="line.2918"></a>
+<span class="sourceLineNo">2919</span>    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();<a name="line.2919"></a>
+<span class="sourceLineNo">2920</span>    String msg = "Finished flush of"<a name="line.2920"></a>
+<span class="sourceLineNo">2921</span>        + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/" + mss.getDataSize()<a name="line.2921"></a>
+<span class="sourceLineNo">2922</span>        + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/" + mss.getHeapSize()<a name="line.2922"></a>
+<span class="sourceLineNo">2923</span>        + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/" + memstoresize<a name="line.2923"></a>
+<span class="sourceLineNo">2924</span>        + " for " + this.getRegionInfo().getEncodedName() + " in " + time + "ms, sequenceid="<a name="line.2924"></a>
+<span class="sourceLineNo">2925</span>        + flushOpSeqId +  ", compaction requested=" + compactionRequested<a name="line.2925"></a>
+<span class="sourceLineNo">2926</span>        + ((wal == null) ? "; wal=null" : "");<a name="line.2926"></a>
+<span class="sourceLineNo">2927</span>    LOG.info(msg);<a name="line.2927"></a>
+<span class="sourceLineNo">2928</span>    status.setStatus(msg);<a name="line.2928"></a>
+<span class="sourceLineNo">2929</span><a name="line.2929"></a>
+<span class="sourceLineNo">2930</span>    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {<a name="line.2930"></a>
+<span class="sourceLineNo">2931</span>      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),<a name="line.2931"></a>
+<span class="sourceLineNo">2932</span>          time,<a name="line.2932"></a>
+<span class="sourceLineNo">2933</span>          mss.getDataSize(), flushedOutputFileSize);<a name="line.2933"></a>
+<span class="sourceLineNo">2934</span>    }<a name="line.2934"></a>
+<span class="sourceLineNo">2935</span><a name="line.2935"></a>
+<span class="sourceLineNo">2936</span>    return new FlushResultImpl(compactionRequested ?<a name="line.2936"></a>
+<span class="sourceLineNo">2937</span>        FlushResult.Result.FLUSHED_COMPACTION_NEEDED :<a name="line.2937"></a>
+<span class="sourceLineNo">2938</span>          FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);<a name="line.2938"></a>
+<span class="sourceLineNo">2939</span>  }<a name="line.2939"></a>
+<span class="sourceLineNo">2940</span><a name="line.2940"></a>
+<span class="sourceLineNo">2941</span>  /**<a name="line.2941"></a>
+<span class="sourceLineNo">2942</span>   * Method to safely get the next sequence number.<a name="line.2942"></a>
+<span class="sourceLineNo">2943</span>   * @return Next sequence number unassociated with any actual edit.<a name="line.2943"></a>
+<span class="sourceLineNo">2944</span>   * @throws IOException<a name="line.2944"></a>
+<span class="sourceLineNo">2945</span>   */<a name="line.2945"></a>
+<span class="sourceLineNo">2946</span>  @VisibleForTesting<a name="line.2946"></a>
+<span class="sourceLineNo">2947</span>  protected long getNextSequenceId(final WAL wal) throws IOException {<a name="line.2947"></a>
+<span class="sourceLineNo">2948</span>    WriteEntry we = mvcc.begin();<a name="line.2948"></a>
+<span class="sourceLineNo">2949</span>    mvcc.completeAndWait(we);<a name="line.2949"></a>
+<span class="sourceLineNo">2950</span>    return we.getWriteNumber();<a name="line.2950"></a>
+<span class="sourceLineNo">2951</span>  }<a name="line.2951"></a>
+<span class="sourceLineNo">2952</span><a name="line.2952"></a>
+<span class="sourceLineNo">2953</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2953"></a>
+<span class="sourceLineNo">2954</span>  // get() methods for client use.<a name="line.2954"></a>
+<span class="sourceLineNo">2955</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.2955"></a>
+<span class="sourceLineNo">2956</span><a name="line.2956"></a>
+<span class="sourceLineNo">2957</span>  @Override<a name="line.2957"></a>
+<span class="sourceLineNo">2958</span>  public RegionScannerImpl getScanner(Scan scan) throws IOException {<a name="line.2958"></a>
+<span class="sourceLineNo">2959</span>   return getScanner(scan, null);<a name="line.2959"></a>
+<span class="sourceLineNo">2960</span>  }<a name="line.2960"></a>
+<span class="sourceLineNo">2961</span><a name="line.2961"></a>
+<span class="sourceLineNo">2962</span>  @Override<a name="line.2962"></a>
+<span class="sourceLineNo">2963</span>  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.2963"></a>
+<span class="sourceLineNo">2964</span>      throws IOException {<a name="line.2964"></a>
+<span class="sourceLineNo">2965</span>    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.2965"></a>
+<span class="sourceLineNo">2966</span>  }<a name="line.2966"></a>
+<span class="sourceLineNo">2967</span><a name="line.2967"></a>
+<span class="sourceLineNo">2968</span>  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,<a name="line.2968"></a>
+<span class="sourceLineNo">2969</span>      long nonceGroup, long nonce) throws IOException {<a name="line.2969"></a>
+<span class="sourceLineNo">2970</span>    startRegionOperation(Operation.SCAN);<a name="line.2970"></a>
+<span class="sourceLineNo">2971</span>    try {<a name="line.2971"></a>
+<span class="sourceLineNo">2972</span>      // Verify families are all valid<a name="line.2972"></a>
+<span class="sourceLineNo">2973</span>      if (!scan.hasFamilies()) {<a name="line.2973"></a>
+<span class="sourceLineNo">2974</span>        // Adding all families to scanner<a name="line.2974"></a>
+<span class="sourceLineNo">2975</span>        for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.2975"></a>
+<span class="sourceLineNo">2976</span>          scan.addFamily(family);<a name="line.2976"></a>
+<span class="sourceLineNo">2977</span>        }<a name="line.2977"></a>
+<span class="sourceLineNo">2978</span>      } else {<a name="line.2978"></a>
+<span class="sourceLineNo">2979</span>        for (byte[] family : scan.getFamilyMap().keySet()) {<a name="line.2979"></a>
+<span class="sourceLineNo">2980</span>          checkFamily(family);<a name="line.2980"></a>
+<span class="sourceLineNo">2981</span>        }<a name="line.2981"></a>
+<span class="sourceLineNo">2982</span>      }<a name="line.2982"></a>
+<span class="sourceLineNo">2983</span>      return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);<a name="line.2983"></a>
+<span class="sourceLineNo">2984</span>    } finally {<a name="line.2984"></a>
+<span class="sourceLineNo">2985</span>      closeRegionOperation(Operation.SCAN);<a name="line.2985"></a>
+<span class="sourceLineNo">2986</span>    }<a name="line.2986"></a>
+<span class="sourceLineNo">2987</span>  }<a name="line.2987"></a>
+<span class="sourceLineNo">2988</span><a name="line.2988"></a>
+<span class="sourceLineNo">2989</span>  protected RegionScanner instantiateRegionScanner(Scan scan,<a name="line.2989"></a>
+<span class="sourceLineNo">2990</span>      List&lt;KeyValueScanner&gt; additionalScanners) throws IOException {<a name="line.2990"></a>
+<span class="sourceLineNo">2991</span>    return instantiateRegionScanner(scan, additionalScanners, HConstants.NO_NONCE,<a name="line.2991"></a>
+<span class="sourceLineNo">2992</span>      HConstants.NO_NONCE);<a name="line.2992"></a>
+<span class="sourceLineNo">2993</span>  }<a name="line.2993"></a>
+<span class="sourceLineNo">2994</span><a name="line.2994"></a>
+<span class="sourceLineNo">2995</span>  protected RegionScannerImpl instantiateRegionScanner(Scan scan,<a name="line.2995"></a>
+<span class="sourceLineNo">2996</span>      List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {<a name="line.2996"></a>
+<span class="sourceLineNo">2997</span>    if (scan.isReversed()) {<a name="line.2997"></a>
+<span class="sourceLineNo">2998</span>      if (scan.getFilter() != null) {<a name="line.2998"></a>
+<span class="sourceLineNo">2999</span>        scan.getFilter().setReversed(true);<a name="line.2999"></a>
+<span class="sourceLineNo">3000</span>      }<a name="line.3000"></a>
+<span class="sourceLineNo">3001</span>      return new ReversedRegionScannerImpl(scan, additionalScanners, this);<a name="line.3001"></a>
+<span class="sourceLineNo">3002</span>    }<a name="line.3002"></a>
+<span class="sourceLineNo">3003</span>    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);<a name="line.3003"></a>
+<span class="sourceLineNo">3004</span>  }<a name="line.3004"></a>
+<span class="sourceLineNo">3005</span><a name="line.3005"></a>
+<span class="sourceLineNo">3006</span>  /**<a name="line.3006"></a>
+<span class="sourceLineNo">3007</span>   * Prepare a delete for a row mutation processor<a name="line.3007"></a>
+<span class="sourceLineNo">3008</span>   * @param delete The passed delete is modified by this method. WARNING!<a name="line.3008"></a>
+<span class="sourceLineNo">3009</span>   * @throws IOException<a name="line.3009"></a>
+<span class="sourceLineNo">3010</span>   */<a name="line.3010"></a>
+<span class="sourceLineNo">3011</span>  public void prepareDelete(Delete delete) throws IOException {<a name="line.3011"></a>
+<span class="sourceLineNo">3012</span>    // Check to see if this is a deleteRow insert<a name="line.3012"></a>
+<span class="sourceLineNo">3013</span>    if(delete.getFamilyCellMap().isEmpty()){<a name="line.3013"></a>
+<span class="sourceLineNo">3014</span>      for(byte [] family : this.htableDescriptor.getColumnFamilyNames()){<a name="line.3014"></a>
+<span class="sourceLineNo">3015</span>        // Don't eat the timestamp<a name="line.3015"></a>
+<span class="sourceLineNo">3016</span>        delete.addFamily(family, delete.getTimestamp());<a name="line.3016"></a>
+<span class="sourceLineNo">3017</span>      }<a name="line.3017"></a>
+<span class="sourceLineNo">3018</span>    } else {<a name="line.3018"></a>
+<span class="sourceLineNo">3019</span>      for(byte [] family : delete.getFamilyCellMap().keySet()) {<a name="line.3019"></a>
+<span class="sourceLineNo">3020</span>        if(family == null) {<a name="line.3020"></a>
+<span class="sourceLineNo">3021</span>          throw new NoSuchColumnFamilyException("Empty family is invalid");<a name="line.3021"></a>
+<span class="sourceLineNo">3022</span>        }<a name="line.3022"></a>
+<span class="sourceLineNo">3023</span>        checkFamily(family, delete.getDurability());<a name="line.3023"></a>
+<span class="sourceLineNo">3024</span>      }<a name="line.3024"></a>
+<span class="sourceLineNo">3025</span>    }<a name="line.3025"></a>
+<span class="sourceLineNo">3026</span>  }<a name="line.3026"></a>
+<span class="sourceLineNo">3027</span><a name="line.3027"></a>
+<span class="sourceLineNo">3028</span>  @Override<a name="line.3028"></a>
+<span class="sourceLineNo">3029</span>  public void delete(Delete delete) throws IOException {<a name="line.3029"></a>
+<span class="sourceLineNo">3030</span>    checkReadOnly();<a name="line.3030"></a>
+<span class="sourceLineNo">3031</span>    checkResources();<a name="line.3031"></a>
+<span class="sourceLineNo">3032</span>    startRegionOperation(Operation.DELETE);<a name="line.3032"></a>
+<span class="sourceLineNo">3033</span>    try {<a name="line.3033"></a>
+<span class="sourceLineNo">3034</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3034"></a>
+<span class="sourceLineNo">3035</span>      doBatchMutate(delete);<a name="line.3035"></a>
+<span class="sourceLineNo">3036</span>    } finally {<a name="line.3036"></a>
+<span class="sourceLineNo">3037</span>      closeRegionOperation(Operation.DELETE);<a name="line.3037"></a>
+<span class="sourceLineNo">3038</span>    }<a name="line.3038"></a>
+<span class="sourceLineNo">3039</span>  }<a name="line.3039"></a>
+<span class="sourceLineNo">3040</span><a name="line.3040"></a>
+<span class="sourceLineNo">3041</span>  /**<a name="line.3041"></a>
+<span class="sourceLineNo">3042</span>   * Row needed by below method.<a name="line.3042"></a>
+<span class="sourceLineNo">3043</span>   */<a name="line.3043"></a>
+<span class="sourceLineNo">3044</span>  private static final byte [] FOR_UNIT_TESTS_ONLY = Bytes.toBytes("ForUnitTestsOnly");<a name="line.3044"></a>
+<span class="sourceLineNo">3045</span><a name="line.3045"></a>
+<span class="sourceLineNo">3046</span>  /**<a name="line.3046"></a>
+<span class="sourceLineNo">3047</span>   * This is used only by unit tests. Not required to be a public API.<a name="line.3047"></a>
+<span class="sourceLineNo">3048</span>   * @param familyMap map of family to edits for the given family.<a name="line.3048"></a>
+<span class="sourceLineNo">3049</span>   * @throws IOException<a name="line.3049"></a>
+<span class="sourceLineNo">3050</span>   */<a name="line.3050"></a>
+<span class="sourceLineNo">3051</span>  void delete(NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3051"></a>
+<span class="sourceLineNo">3052</span>      Durability durability) throws IOException {<a name="line.3052"></a>
+<span class="sourceLineNo">3053</span>    Delete delete = new Delete(FOR_UNIT_TESTS_ONLY, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.3053"></a>
+<span class="sourceLineNo">3054</span>    delete.setDurability(durability);<a name="line.3054"></a>
+<span class="sourceLineNo">3055</span>    doBatchMutate(delete);<a name="line.3055"></a>
+<span class="sourceLineNo">3056</span>  }<a name="line.3056"></a>
+<span class="sourceLineNo">3057</span><a name="line.3057"></a>
+<span class="sourceLineNo">3058</span>  /**<a name="line.3058"></a>
+<span class="sourceLineNo">3059</span>   * Set up correct timestamps in the KVs in Delete object.<a name="line.3059"></a>
+<span class="sourceLineNo">3060</span>   * &lt;p&gt;Caller should have the row and region locks.<a name="line.3060"></a>
+<span class="sourceLineNo">3061</span>   * @param mutation<a name="line.3061"></a>
+<span class="sourceLineNo">3062</span>   * @param familyMap<a name="line.3062"></a>
+<span class="sourceLineNo">3063</span>   * @param byteNow<a name="line.3063"></a>
+<span class="sourceLineNo">3064</span>   * @throws IOException<a name="line.3064"></a>
+<span class="sourceLineNo">3065</span>   */<a name="line.3065"></a>
+<span class="sourceLineNo">3066</span>  public void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3066"></a>
+<span class="sourceLineNo">3067</span>      byte[] byteNow) throws IOException {<a name="line.3067"></a>
+<span class="sourceLineNo">3068</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3068"></a>
+<span class="sourceLineNo">3069</span><a name="line.3069"></a>
+<span class="sourceLineNo">3070</span>      byte[] family = e.getKey();<a name="line.3070"></a>
+<span class="sourceLineNo">3071</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.3071"></a>
+<span class="sourceLineNo">3072</span>      assert cells instanceof RandomAccess;<a name="line.3072"></a>
+<span class="sourceLineNo">3073</span><a name="line.3073"></a>
+<span class="sourceLineNo">3074</span>      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.3074"></a>
+<span class="sourceLineNo">3075</span>      int listSize = cells.size();<a name="line.3075"></a>
+<span class="sourceLineNo">3076</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.3076"></a>
+<span class="sourceLineNo">3077</span>        Cell cell = cells.get(i);<a name="line.3077"></a>
+<span class="sourceLineNo">3078</span>        //  Check if time is LATEST, change to time of most recent addition if so<a name="line.3078"></a>
+<span class="sourceLineNo">3079</span>        //  This is expensive.<a name="line.3079"></a>
+<span class="sourceLineNo">3080</span>        if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP<a name="line.3080"></a>
+<span class="sourceLineNo">3081</span>            &amp;&amp; PrivateCellUtil.isDeleteType(cell)) {<a name="line.3081"></a>
+<span class="sourceLineNo">3082</span>          byte[] qual = CellUtil.cloneQualifier(cell);<a name="line.3082"></a>
+<span class="sourceLineNo">3083</span><a name="line.3083"></a>
+<span class="sourceLineNo">3084</span>          Integer count = kvCount.get(qual);<a name="line.3084"></a>
+<span class="sourceLineNo">3085</span>          if (count == null) {<a name="line.3085"></a>
+<span class="sourceLineNo">3086</span>            kvCount.put(qual, 1);<a name="line.3086"></a>
+<span class="sourceLineNo">3087</span>          } else {<a name="line.3087"></a>
+<span class="sourceLineNo">3088</span>            kvCount.put(qual, count + 1);<a name="line.3088"></a>
+<span class="sourceLineNo">3089</span>          }<a name="line.3089"></a>
+<span class="sourceLineNo">3090</span>          count = kvCount.get(qual);<a name="line.3090"></a>
+<span class="sourceLineNo">3091</span><a name="line.3091"></a>
+<span class="sourceLineNo">3092</span>          Get get = new Get(CellUtil.cloneRow(cell));<a name="line.3092"></a>
+<span class="sourceLineNo">3093</span>          get.readVersions(count);<a name="line.3093"></a>
+<span class="sourceLineNo">3094</span>          get.addColumn(family, qual);<a name="line.3094"></a>
+<span class="sourceLineNo">3095</span>          if (coprocessorHost != null) {<a name="line.3095"></a>
+<span class="sourceLineNo">3096</span>            if (!coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell,<a name="line.3096"></a>
+<span class="sourceLineNo">3097</span>                byteNow, get)) {<a name="line.3097"></a>
+<span class="sourceLineNo">3098</span>              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3098"></a>
+<span class="sourceLineNo">3099</span>            }<a name="line.3099"></a>
+<span class="sourceLineNo">3100</span>          } else {<a name="line.3100"></a>
+<span class="sourceLineNo">3101</span>            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);<a name="line.3101"></a>
+<span class="sourceLineNo">3102</span>          }<a name="line.3102"></a>
+<span class="sourceLineNo">3103</span>        } else {<a name="line.3103"></a>
+<span class="sourceLineNo">3104</span>          PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3104"></a>
+<span class="sourceLineNo">3105</span>        }<a name="line.3105"></a>
+<span class="sourceLineNo">3106</span>      }<a name="line.3106"></a>
+<span class="sourceLineNo">3107</span>    }<a name="line.3107"></a>
+<span class="sourceLineNo">3108</span>  }<a name="line.3108"></a>
+<span class="sourceLineNo">3109</span><a name="line.3109"></a>
+<span class="sourceLineNo">3110</span>  void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)<a name="line.3110"></a>
+<span class="sourceLineNo">3111</span>      throws IOException {<a name="line.3111"></a>
+<span class="sourceLineNo">3112</span>    List&lt;Cell&gt; result = get(get, false);<a name="line.3112"></a>
+<span class="sourceLineNo">3113</span><a name="line.3113"></a>
+<span class="sourceLineNo">3114</span>    if (result.size() &lt; count) {<a name="line.3114"></a>
+<span class="sourceLineNo">3115</span>      // Nothing to delete<a name="line.3115"></a>
+<span class="sourceLineNo">3116</span>      PrivateCellUtil.updateLatestStamp(cell, byteNow);<a name="line.3116"></a>
+<span class="sourceLineNo">3117</span>      return;<a name="line.3117"></a>
 <span class="sourceLineNo">3118</span>    }<a name="line.3118"></a>
-<span class="sourceLineNo">3119</span>    Cell getCell = result.get(count - 1);<a name="line.3119"></a>
-<span class="sourceLineNo">3120</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3120"></a>
-<span class="sourceLineNo">3121</span>  }<a name="line.3121"></a>
-<span class="sourceLineNo">3122</span><a name="line.3122"></a>
-<span class="sourceLineNo">3123</span>  @Override<a name="line.3123"></a>
-<span class="sourceLineNo">3124</span>  public void put(Put put) throws IOException {<a name="line.3124"></a>
-<span class="sourceLineNo">3125</span>    checkReadOnly();<a name="line.3125"></a>
-<span class="sourceLineNo">3126</span><a name="line.3126"></a>
-<span class="sourceLineNo">3127</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3127"></a>
-<span class="sourceLineNo">3128</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3128"></a>
-<span class="sourceLineNo">3129</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3129"></a>
-<span class="sourceLineNo">3130</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3130"></a>
-<span class="sourceLineNo">3131</span>    checkResources();<a name="line.3131"></a>
-<span class="sourceLineNo">3132</span>    startRegionOperation(Operation.PUT);<a name="line.3132"></a>
-<span class="sourceLineNo">3133</span>    try {<a name="line.3133"></a>
-<span class="sourceLineNo">3134</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3134"></a>
-<span class="sourceLineNo">3135</span>      doBatchMutate(put);<a name="line.3135"></a>
-<span class="sourceLineNo">3136</span>    } finally {<a name="line.3136"></a>
-<span class="sourceLineNo">3137</span>      closeRegionOperation(Operation.PUT);<a name="line.3137"></a>
-<span class="sourceLineNo">3138</span>    }<a name="line.3138"></a>
-<span class="sourceLineNo">3139</span>  }<a name="line.3139"></a>
-<span class="sourceLineNo">3140</span><a name="line.3140"></a>
-<span class="sourceLineNo">3141</span>  /**<a name="line.3141"></a>
-<span class="sourceLineNo">3142</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3142"></a>
-<span class="sourceLineNo">3143</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3143"></a>
-<span class="sourceLineNo">3144</span>   * mini-batches for processing.<a name="line.3144"></a>
-<span class="sourceLineNo">3145</span>   */<a name="line.3145"></a>
-<span class="sourceLineNo">3146</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3146"></a>
-<span class="sourceLineNo">3147</span>    protected final T[] operations;<a name="line.3147"></a>
-<span class="sourceLineNo">3148</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3148"></a>
-<span class="sourceLineNo">3149</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3149"></a>
-<span class="sourceLineNo">3150</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3150"></a>
-<span class="sourceLineNo">3151</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3151"></a>
-<span class="sourceLineNo">3152</span><a name="line.3152"></a>
-<span class="sourceLineNo">3153</span>    protected final HRegion region;<a name="line.3153"></a>
-<span class="sourceLineNo">3154</span>    protected int nextIndexToProcess = 0;<a name="line.3154"></a>
-<span class="sourceLineNo">3155</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3155"></a>
-<span class="sourceLineNo">3156</span>    //Durability of the batch (highest durability of all operations)<a name="line.3156"></a>
-<span class="sourceLineNo">3157</span>    protected Durability durability;<a name="line.3157"></a>
-<span class="sourceLineNo">3158</span>    protected boolean atomic = false;<a name="line.3158"></a>
-<span class="sourceLineNo">3159</span><a name="line.3159"></a>
-<span class="sourceLineNo">3160</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3160"></a>
-<span class="sourceLineNo">3161</span>      this.operations = operations;<a name="line.3161"></a>
-<span class="sourceLineNo">3162</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3162"></a>
-<span class="sourceLineNo">3163</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3163"></a>
-<span class="sourceLineNo">3164</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3164"></a>
-<span class="sourceLineNo">3165</span>      familyCellMaps = new Map[operations.length];<a name="line.3165"></a>
-<span class="sourceLineNo">3166</span><a name="line.3166"></a>
-<span class="sourceLineNo">3167</span>      this.region = region;<a name="line.3167"></a>
-<span class="sourceLineNo">3168</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3168"></a>
-<span class="sourceLineNo">3169</span>      durability = Durability.USE_DEFAULT;<a name="line.3169"></a>
-<span class="sourceLineNo">3170</span>    }<a name="line.3170"></a>
-<span class="sourceLineNo">3171</span><a name="line.3171"></a>
-<span class="sourceLineNo">3172</span>    /**<a name="line.3172"></a>
-<span class="sourceLineNo">3173</span>     * Visitor interface for batch operations<a name="line.3173"></a>
-<span class="sourceLineNo">3174</span>     */<a name="line.3174"></a>
-<span class="sourceLineNo">3175</span>    @FunctionalInterface<a name="line.3175"></a>
-<span class="sourceLineNo">3176</span>    public interface Visitor {<a name="line.3176"></a>
-<span class="sourceLineNo">3177</span>      /**<a name="line.3177"></a>
-<span class="sourceLineNo">3178</span>       * @param index operation index<a name="line.3178"></a>
-<span class="sourceLineNo">3179</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3179"></a>
-<span class="sourceLineNo">3180</span>       */<a name="line.3180"></a>
-<span class="sourceLineNo">3181</span>      boolean visit(int index) throws IOException;<a name="line.3181"></a>
-<span class="sourceLineNo">3182</span>    }<a name="line.3182"></a>
-<span class="sourceLineNo">3183</span><a name="line.3183"></a>
-<span class="sourceLineNo">3184</span>    /**<a name="line.3184"></a>
-<span class="sourceLineNo">3185</span>     * Helper method for visiting pending/ all batch operations<a name="line.3185"></a>
-<span class="sourceLineNo">3186</span>     */<a name="line.3186"></a>
-<span class="sourceLineNo">3187</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3187"></a>
-<span class="sourceLineNo">3188</span>        throws IOException {<a name="line.3188"></a>
-<span class="sourceLineNo">3189</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3189"></a>
-<span class="sourceLineNo">3190</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3190"></a>
-<span class="sourceLineNo">3191</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3191"></a>
-<span class="sourceLineNo">3192</span>          if (!visitor.visit(i)) {<a name="line.3192"></a>
-<span class="sourceLineNo">3193</span>            break;<a name="line.3193"></a>
-<span class="sourceLineNo">3194</span>          }<a name="line.3194"></a>
-<span class="sourceLineNo">3195</span>        }<a name="line.3195"></a>
-<span class="sourceLineNo">3196</span>      }<a name="line.3196"></a>
-<span class="sourceLineNo">3197</span>    }<a name="line.3197"></a>
-<span class="sourceLineNo">3198</span><a name="line.3198"></a>
-<span class="sourceLineNo">3199</span>    public abstract Mutation getMutation(int index);<a name="line.3199"></a>
-<span class="sourceLineNo">3200</span><a name="line.3200"></a>
-<span class="sourceLineNo">3201</span>    public abstract long getNonceGroup(int index);<a name="line.3201"></a>
-<span class="sourceLineNo">3202</span><a name="line.3202"></a>
-<span class="sourceLineNo">3203</span>    public abstract long getNonce(int index);<a name="line.3203"></a>
-<span class="sourceLineNo">3204</span><a name="line.3204"></a>
-<span class="sourceLineNo">3205</span>    /**<a name="line.3205"></a>
-<span class="sourceLineNo">3206</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3206"></a>
-<span class="sourceLineNo">3207</span>     */<a name="line.3207"></a>
-<span class="sourceLineNo">3208</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3208"></a>
-<span class="sourceLineNo">3209</span><a name="line.3209"></a>
-<span class="sourceLineNo">3210</span>    public abstract boolean isInReplay();<a name="line.3210"></a>
-<span class="sourceLineNo">3211</span><a name="line.3211"></a>
-<span class="sourceLineNo">3212</span>    public abstract long getOrigLogSeqNum();<a name="line.3212"></a>
-<span class="sourceLineNo">3213</span><a name="line.3213"></a>
-<span class="sourceLineNo">3214</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3214"></a>
-<span class="sourceLineNo">3215</span><a name="line.3215"></a>
-<span class="sourceLineNo">3216</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3216"></a>
-<span class="sourceLineNo">3217</span><a name="line.3217"></a>
-<span class="sourceLineNo">3218</span>    /**<a name="line.3218"></a>
-<span class="sourceLineNo">3219</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3219"></a>
-<span class="sourceLineNo">3220</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3220"></a>
-<span class="sourceLineNo">3221</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3221"></a>
-<span class="sourceLineNo">3222</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3222"></a>
-<span class="sourceLineNo">3223</span>     * 'for' loop over mutations.<a name="line.3223"></a>
-<span class="sourceLineNo">3224</span>     */<a name="line.3224"></a>
-<span class="sourceLineNo">3225</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3225"></a>
-<span class="sourceLineNo">3226</span><a name="line.3226"></a>
-<span class="sourceLineNo">3227</span>    /**<a name="line.3227"></a>
-<span class="sourceLineNo">3228</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3228"></a>
-<span class="sourceLineNo">3229</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3229"></a>
-<span class="sourceLineNo">3230</span>     */<a name="line.3230"></a>
-<span class="sourceLineNo">3231</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3231"></a>
-<span class="sourceLineNo">3232</span><a name="line.3232"></a>
-<span class="sourceLineNo">3233</span>    /**<a name="line.3233"></a>
-<span class="sourceLineNo">3234</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3234"></a>
-<span class="sourceLineNo">3235</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3235"></a>
-<span class="sourceLineNo">3236</span>     */<a name="line.3236"></a>
-<span class="sourceLineNo">3237</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3237"></a>
-<span class="sourceLineNo">3238</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3238"></a>
-<span class="sourceLineNo">3239</span><a name="line.3239"></a>
-<span class="sourceLineNo">3240</span>    /**<a name="line.3240"></a>
-<span class="sourceLineNo">3241</span>     * Write mini-batch operations to MemStore<a name="line.3241"></a>
-<span class="sourceLineNo">3242</span>     */<a name="line.3242"></a>
-<span class="sourceLineNo">3243</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3243"></a>
-<span class="sourceLineNo">3244</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3244"></a>
-<span class="sourceLineNo">3245</span>        throws IOException;<a name="line.3245"></a>
-<span class="sourceLineNo">3246</span><a name="line.3246"></a>
-<span class="sourceLineNo">3247</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3247"></a>
-<span class="sourceLineNo">3248</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3248"></a>
-<span class="sourceLineNo">3249</span>        throws IOException {<a name="line.3249"></a>
-<span class="sourceLineNo">3250</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3250"></a>
-<span class="sourceLineNo">3251</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3251"></a>
-<span class="sourceLineNo">3252</span>        // We need to update the sequence id for following reasons.<a name="line.3252"></a>
-<span class="sourceLineNo">3253</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3253"></a>
-<span class="sourceLineNo">3254</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3254"></a>
-<span class="sourceLineNo">3255</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3255"></a>
-<span class="sourceLineNo">3256</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3256"></a>
-<span class="sourceLineNo">3257</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3257"></a>
-<span class="sourceLineNo">3258</span>        }<a name="line.3258"></a>
-<span class="sourceLineNo">3259</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3259"></a>
-<span class="sourceLineNo">3260</span>        return true;<a name="line.3260"></a>
-<span class="sourceLineNo">3261</span>      });<a name="line.3261"></a>
-<span class="sourceLineNo">3262</span>      // update memStore size<a name="line.3262"></a>
-<span class="sourceLineNo">3263</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3263"></a>
-<span class="sourceLineNo">3264</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3264"></a>
-<span class="sourceLineNo">3265</span>    }<a name="line.3265"></a>
-<span class="sourceLineNo">3266</span><a name="line.3266"></a>
-<span class="sourceLineNo">3267</span>    public boolean isDone() {<a name="line.3267"></a>
-<span class="sourceLineNo">3268</span>      return nextIndexToProcess == operations.length;<a name="line.3268"></a>
-<span class="sourceLineNo">3269</span>    }<a name="line.3269"></a>
-<span class="sourceLineNo">3270</span><a name="line.3270"></a>
-<span class="sourceLineNo">3271</span>    public int size() {<a name="line.3271"></a>
-<span class="sourceLineNo">3272</span>      return operations.length;<a name="line.3272"></a>
-<span class="sourceLineNo">3273</span>    }<a name="line.3273"></a>
-<span class="sourceLineNo">3274</span><a name="line.3274"></a>
-<span class="sourceLineNo">3275</span>    public boolean isOperationPending(int index) {<a name="line.3275"></a>
-<span class="sourceLineNo">3276</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3276"></a>
-<span class="sourceLineNo">3277</span>    }<a name="line.3277"></a>
-<span class="sourceLineNo">3278</span><a name="line.3278"></a>
-<span class="sourceLineNo">3279</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3279"></a>
-<span class="sourceLineNo">3280</span>      assert size() != 0;<a name="line.3280"></a>
-<span class="sourceLineNo">3281</span>      return getMutation(0).getClusterIds();<a name="line.3281"></a>
-<span class="sourceLineNo">3282</span>    }<a name="line.3282"></a>
-<span class="sourceLineNo">3283</span><a name="line.3283"></a>
-<span class="sourceLineNo">3284</span>    boolean isAtomic() {<a name="line.3284"></a>
-<span class="sourceLineNo">3285</span>      return atomic;<a name="line.3285"></a>
-<span class="sourceLineNo">3286</span>    }<a name="line.3286"></a>
-<span class="sourceLineNo">3287</span><a name="line.3287"></a>
-<span class="sourceLineNo">3288</span>    /**<a name="line.3288"></a>
-<span class="sourceLineNo">3289</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3289"></a>
-<span class="sourceLineNo">3290</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3290"></a>
-<span class="sourceLineNo">3291</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3291"></a>
-<span class="sourceLineNo">3292</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3292"></a>
-<span class="sourceLineNo">3293</span>     */<a name="line.3293"></a>
-<span class="sourceLineNo">3294</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3294"></a>
-<span class="sourceLineNo">3295</span>        throws IOException {<a name="line.3295"></a>
-<span class="sourceLineNo">3296</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3296"></a>
-<span class="sourceLineNo">3297</span>      if (mutation instanceof Put) {<a name="line.3297"></a>
-<span class="sourceLineNo">3298</span>        // Check the families in the put. If bad, skip this one.<a name="line.3298"></a>
-<span class="sourceLineNo">3299</span>        checkAndPreparePut((Put) mutation);<a name="line.3299"></a>
-<span class="sourceLineNo">3300</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3300"></a>
-<span class="sourceLineNo">3301</span>      } else {<a name="line.3301"></a>
-<span class="sourceLineNo">3302</span>        region.prepareDelete((Delete) mutation);<a name="line.3302"></a>
-<span class="sourceLineNo">3303</span>      }<a name="line.3303"></a>
-<span class="sourceLineNo">3304</span>    }<a name="line.3304"></a>
-<span class="sourceLineNo">3305</span><a name="line.3305"></a>
-<span class="sourceLineNo">3306</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3306"></a>
-<span class="sourceLineNo">3307</span>      Mutation mutation = getMutation(index);<a name="line.3307"></a>
-<span class="sourceLineNo">3308</span>      try {<a name="line.3308"></a>
-<span class="sourceLineNo">3309</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3309"></a>
-<span class="sourceLineNo">3310</span><a name="line.3310"></a>
-<span class="sourceLineNo">3311</span>        // store the family map reference to allow for mutations<a name="line.3311"></a>
-<span class="sourceLineNo">3312</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3312"></a>
-<span class="sourceLineNo">3313</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3313"></a>
-<span class="sourceLineNo">3314</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3314"></a>
-<span class="sourceLineNo">3315</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3315"></a>
-<span class="sourceLineNo">3316</span>          durability = tmpDur;<a name="line.3316"></a>
-<span class="sourceLineNo">3317</span>        }<a name="line.3317"></a>
-<span class="sourceLineNo">3318</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3318"></a>
-<span class="sourceLineNo">3319</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3319"></a>
-<span class="sourceLineNo">3320</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3320"></a>
-<span class="sourceLineNo">3321</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3321"></a>
-<span class="sourceLineNo">3322</span>        } else {<a name="line.3322"></a>
-<span class="sourceLineNo">3323</span>          LOG.warn(msg, nscfe);<a name="line.3323"></a>
-<span class="sourceLineNo">3324</span>          observedExceptions.sawNoSuchFamily();<a name="line.3324"></a>
-<span class="sourceLineNo">3325</span>        }<a name="line.3325"></a>
-<span class="sourceLineNo">3326</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3326"></a>
-<span class="sourceLineNo">3327</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3327"></a>
-<span class="sourceLineNo">3328</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3328"></a>
-<span class="sourceLineNo">3329</span>          throw nscfe;<a name="line.3329"></a>
-<span class="sourceLineNo">3330</span>        }<a name="line.3330"></a>
-<span class="sourceLineNo">3331</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3331"></a>
-<span class="sourceLineNo">3332</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3332"></a>
-<span class="sourceLineNo">3333</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3333"></a>
-<span class="sourceLineNo">3334</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3334"></a>
-<span class="sourceLineNo">3335</span>        } else {<a name="line.3335"></a>
-<span class="sourceLineNo">3336</span>          LOG.warn(msg, fsce);<a name="line.3336"></a>
-<span class="sourceLineNo">3337</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3337"></a>
-<span class="sourceLineNo">3338</span>        }<a name="line.3338"></a>
-<span class="sourceLineNo">3339</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3339"></a>
-<span class="sourceLineNo">3340</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3340"></a>
-<span class="sourceLineNo">3341</span>        if (isAtomic()) {<a name="line.3341"></a>
-<span class="sourceLineNo">3342</span>          throw fsce;<a name="line.3342"></a>
-<span class="sourceLineNo">3343</span>        }<a name="line.3343"></a>
-<span class="sourceLineNo">3344</span>      } catch (WrongRegionException we) {<a name="line.3344"></a>
-<span class="sourceLineNo">3345</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3345"></a>
-<span class="sourceLineNo">3346</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3346"></a>
-<span class="sourceLineNo">3347</span>          LOG.warn(msg + we.getMessage());<a name="line.3347"></a>
-<span class="sourceLineNo">3348</span>        } else {<a name="line.3348"></a>
-<span class="sourceLineNo">3349</span>          LOG.warn(msg, we);<a name="line.3349"></a>
-<span class="sourceLineNo">3350</span>          observedExceptions.sawWrongRegion();<a name="line.3350"></a>
-<span class="sourceLineNo">3351</span>        }<a name="line.3351"></a>
-<span class="sourceLineNo">3352</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3352"></a>
-<span class="sourceLineNo">3353</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3353"></a>
-<span class="sourceLineNo">3354</span>        if (isAtomic()) {<a name="line.3354"></a>
-<span class="sourceLineNo">3355</span>          throw we;<a name="line.3355"></a>
-<span class="sourceLineNo">3356</span>        }<a name="line.3356"></a>
-<span class="sourceLineNo">3357</span>      }<a name="line.3357"></a>
-<span class="sourceLineNo">3358</span>    }<a name="line.3358"></a>
-<span class="sourceLineNo">3359</span><a name="line.3359"></a>
-<span class="sourceLineNo">3360</span>    /**<a name="line.3360"></a>
-<span class="sourceLineNo">3361</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3361"></a>
-<span class="sourceLineNo">3362</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3362"></a>
-<span class="sourceLineNo">3363</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3363"></a>
-<span class="sourceLineNo">3364</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3364"></a>
-<span class="sourceLineNo">3365</span>     *<a name="line.3365"></a>
-<span class="sourceLineNo">3366</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3366"></a>
-<span class="sourceLineNo">3367</span>     */<a name="line.3367"></a>
-<span class="sourceLineNo">3368</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3368"></a>
-<span class="sourceLineNo">3369</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3369"></a>
-<span class="sourceLineNo">3370</span>      int readyToWriteCount = 0;<a name="line.3370"></a>
-<span class="sourceLineNo">3371</span>      int lastIndexExclusive = 0;<a name="line.3371"></a>
-<span class="sourceLineNo">3372</span>      RowLock prevRowLock = null;<a name="line.3372"></a>
-<span class="sourceLineNo">3373</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3373"></a>
-<span class="sourceLineNo">3374</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3374"></a>
-<span class="sourceLineNo">3375</span>        // This only applies to non-atomic batch operations.<a name="line.3375"></a>
-<span class="sourceLineNo">3376</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3376"></a>
-<span class="sourceLineNo">3377</span>          break;<a name="line.3377"></a>
-<span class="sourceLineNo">3378</span>        }<a name="line.3378"></a>
-<span class="sourceLineNo">3379</span><a name="line.3379"></a>
-<span class="sourceLineNo">3380</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3380"></a>
-<span class="sourceLineNo">3381</span>          continue;<a name="line.3381"></a>
-<span class="sourceLineNo">3382</span>        }<a name="line.3382"></a>
-<span class="sourceLineNo">3383</span><a name="line.3383"></a>
-<span class="sourceLineNo">3384</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3384"></a>
-<span class="sourceLineNo">3385</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3385"></a>
-<span class="sourceLineNo">3386</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3386"></a>
-<span class="sourceLineNo">3387</span>        // pass the isOperationPending check<a name="line.3387"></a>
-<span class="sourceLineNo">3388</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3388"></a>
-<span class="sourceLineNo">3389</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3389"></a>
-<span class="sourceLineNo">3390</span>        try {<a name="line.3390"></a>
-<span class="sourceLineNo">3391</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3391"></a>
-<span class="sourceLineNo">3392</span>          // it when encountering exception<a name="line.3392"></a>
-<span class="sourceLineNo">3393</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3393"></a>
-<span class="sourceLineNo">3394</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3394"></a>
-<span class="sourceLineNo">3395</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3395"></a>
-<span class="sourceLineNo">3396</span>          if (isAtomic()) {<a name="line.3396"></a>
-<span class="sourceLineNo">3397</span>            throw rtbe;<a name="line.3397"></a>
-<span class="sourceLineNo">3398</span>          }<a name="line.3398"></a>
-<span class="sourceLineNo">3399</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3399"></a>
-<span class="sourceLineNo">3400</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3400"></a>
-<span class="sourceLineNo">3401</span>          continue;<a name="line.3401"></a>
-<span class="sourceLineNo">3402</span>        }<a name="line.3402"></a>
-<span class="sourceLineNo">3403</span><a name="line.3403"></a>
-<span class="sourceLineNo">3404</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3404"></a>
-<span class="sourceLineNo">3405</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3405"></a>
-<span class="sourceLineNo">3406</span>        RowLock rowLock = null;<a name="line.3406"></a>
-<span class="sourceLineNo">3407</span>        boolean throwException = false;<a name="line.3407"></a>
-<span class="sourceLineNo">3408</span>        try {<a name="line.3408"></a>
-<span class="sourceLineNo">3409</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3409"></a>
-<span class="sourceLineNo">3410</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3410"></a>
-<span class="sourceLineNo">3411</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3411"></a>
-<span class="sourceLineNo">3412</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3412"></a>
-<span class="sourceLineNo">3413</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3413"></a>
-<span class="sourceLineNo">3414</span>          // interrupted respectively.<a name="line.3414"></a>
-<span class="sourceLineNo">3415</span>          throwException = true;<a name="line.3415"></a>
-<span class="sourceLineNo">3416</span>          throw e;<a name="line.3416"></a>
-<span class="sourceLineNo">3417</span>        } catch (IOException ioe) {<a name="line.3417"></a>
-<span class="sourceLineNo">3418</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3418"></a>
-<span class="sourceLineNo">3419</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3419"></a>
-<span class="sourceLineNo">3420</span>            throwException = true;<a name="line.3420"></a>
-<span class="sourceLineNo">3421</span>            throw ioe;<a name="line.3421"></a>
-<span class="sourceLineNo">3422</span>          }<a name="line.3422"></a>
-<span class="sourceLineNo">3423</span>        } catch (Throwable throwable) {<a name="line.3423"></a>
-<span class="sourceLineNo">3424</span>          throwException = true;<a name="line.3424"></a>
-<span class="sourceLineNo">3425</span>          throw throwable;<a name="line.3425"></a>
-<span class="sourceLineNo">3426</span>        } finally {<a name="line.3426"></a>
-<span class="sourceLineNo">3427</span>          if (throwException) {<a name="line.3427"></a>
-<span class="sourceLineNo">3428</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3428"></a>
-<span class="sourceLineNo">3429</span>          }<a name="line.3429"></a>
-<span class="sourceLineNo">3430</span>        }<a name="line.3430"></a>
-<span class="sourceLineNo">3431</span>        if (rowLock == null) {<a name="line.3431"></a>
-<span class="sourceLineNo">3432</span>          // We failed to grab another lock<a name="line.3432"></a>
-<span class="sourceLineNo">3433</span>          if (isAtomic()) {<a name="line.3433"></a>
-<span class="sourceLineNo">3434</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3434"></a>
-<span class="sourceLineNo">3435</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3435"></a>
-<span class="sourceLineNo">3436</span>          }<a name="line.3436"></a>
-<span class="sourceLineNo">3437</span>          break; // Stop acquiring more rows for this batch<a name="line.3437"></a>
-<span class="sourceLineNo">3438</span>        } else {<a name="line.3438"></a>
-<span class="sourceLineNo">3439</span>          if (rowLock != prevRowLock) {<a name="line.3439"></a>
-<span class="sourceLineNo">3440</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3440"></a>
-<span class="sourceLineNo">3441</span>            // set prevRowLock to the new returned rowLock<a name="line.3441"></a>
-<span class="sourceLineNo">3442</span>            acquiredRowLocks.add(rowLock);<a name="line.3442"></a>
-<span class="sourceLineNo">3443</span>            prevRowLock = rowLock;<a name="line.3443"></a>
-<span class="sourceLineNo">3444</span>          }<a name="line.3444"></a>
-<span class="sourceLineNo">3445</span>        }<a name="line.3445"></a>
-<span class="sourceLineNo">3446</span><a name="line.3446"></a>
-<span class="sourceLineNo">3447</span>        readyToWriteCount++;<a name="line.3447"></a>
-<span class="sourceLineNo">3448</span>      }<a name="line.3448"></a>
-<span class="sourceLineNo">3449</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3449"></a>
-<span class="sourceLineNo">3450</span>    }<a name="line.3450"></a>
-<span class="sourceLineNo">3451</span><a name="line.3451"></a>
-<span class="sourceLineNo">3452</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3452"></a>
-<span class="sourceLineNo">3453</span>        final int readyToWriteCount) {<a name="line.3453"></a>
-<span class="sourceLineNo">3454</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3454"></a>
-<span class="sourceLineNo">3455</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3455"></a>
-<span class="sourceLineNo">3456</span>    }<a name="line.3456"></a>
-<span class="sourceLineNo">3457</span><a name="line.3457"></a>
-<span class="sourceLineNo">3458</span>    /**<a name="line.3458"></a>
-<span class="sourceLineNo">3459</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3459"></a>
-<span class="sourceLineNo">3460</span>     * present, they are merged to result WALEdit.<a name="line.3460"></a>
-<span class="sourceLineNo">3461</span>     */<a name="line.3461"></a>
-<span class="sourceLineNo">3462</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3462"></a>
-<span class="sourceLineNo">3463</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3463"></a>
-<span class="sourceLineNo">3464</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3464"></a>
-<span class="sourceLineNo">3465</span><a name="line.3465"></a>
-<span class="sourceLineNo">3466</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3466"></a>
-<span class="sourceLineNo">3467</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3467"></a>
+<span class="sourceLineNo">3119</span>    if (result.size() &gt; count) {<a name="line.3119"></a>
+<span class="sourceLineNo">3120</span>      throw new RuntimeException("Unexpected size: " + result.size());<a name="line.3120"></a>
+<span class="sourceLineNo">3121</span>    }<a name="line.3121"></a>
+<span class="sourceLineNo">3122</span>    Cell getCell = result.get(count - 1);<a name="line.3122"></a>
+<span class="sourceLineNo">3123</span>    PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());<a name="line.3123"></a>
+<span class="sourceLineNo">3124</span>  }<a name="line.3124"></a>
+<span class="sourceLineNo">3125</span><a name="line.3125"></a>
+<span class="sourceLineNo">3126</span>  @Override<a name="line.3126"></a>
+<span class="sourceLineNo">3127</span>  public void put(Put put) throws IOException {<a name="line.3127"></a>
+<span class="sourceLineNo">3128</span>    checkReadOnly();<a name="line.3128"></a>
+<span class="sourceLineNo">3129</span><a name="line.3129"></a>
+<span class="sourceLineNo">3130</span>    // Do a rough check that we have resources to accept a write.  The check is<a name="line.3130"></a>
+<span class="sourceLineNo">3131</span>    // 'rough' in that between the resource check and the call to obtain a<a name="line.3131"></a>
+<span class="sourceLineNo">3132</span>    // read lock, resources may run out.  For now, the thought is that this<a name="line.3132"></a>
+<span class="sourceLineNo">3133</span>    // will be extremely rare; we'll deal with it when it happens.<a name="line.3133"></a>
+<span class="sourceLineNo">3134</span>    checkResources();<a name="line.3134"></a>
+<span class="sourceLineNo">3135</span>    startRegionOperation(Operation.PUT);<a name="line.3135"></a>
+<span class="sourceLineNo">3136</span>    try {<a name="line.3136"></a>
+<span class="sourceLineNo">3137</span>      // All edits for the given row (across all column families) must happen atomically.<a name="line.3137"></a>
+<span class="sourceLineNo">3138</span>      doBatchMutate(put);<a name="line.3138"></a>
+<span class="sourceLineNo">3139</span>    } finally {<a name="line.3139"></a>
+<span class="sourceLineNo">3140</span>      closeRegionOperation(Operation.PUT);<a name="line.3140"></a>
+<span class="sourceLineNo">3141</span>    }<a name="line.3141"></a>
+<span class="sourceLineNo">3142</span>  }<a name="line.3142"></a>
+<span class="sourceLineNo">3143</span><a name="line.3143"></a>
+<span class="sourceLineNo">3144</span>  /**<a name="line.3144"></a>
+<span class="sourceLineNo">3145</span>   * Class that tracks the progress of a batch operations, accumulating status codes and tracking<a name="line.3145"></a>
+<span class="sourceLineNo">3146</span>   * the index at which processing is proceeding. These batch operations may get split into<a name="line.3146"></a>
+<span class="sourceLineNo">3147</span>   * mini-batches for processing.<a name="line.3147"></a>
+<span class="sourceLineNo">3148</span>   */<a name="line.3148"></a>
+<span class="sourceLineNo">3149</span>  private abstract static class BatchOperation&lt;T&gt; {<a name="line.3149"></a>
+<span class="sourceLineNo">3150</span>    protected final T[] operations;<a name="line.3150"></a>
+<span class="sourceLineNo">3151</span>    protected final OperationStatus[] retCodeDetails;<a name="line.3151"></a>
+<span class="sourceLineNo">3152</span>    protected final WALEdit[] walEditsFromCoprocessors;<a name="line.3152"></a>
+<span class="sourceLineNo">3153</span>    // reference family cell maps directly so coprocessors can mutate them if desired<a name="line.3153"></a>
+<span class="sourceLineNo">3154</span>    protected final Map&lt;byte[], List&lt;Cell&gt;&gt;[] familyCellMaps;<a name="line.3154"></a>
+<span class="sourceLineNo">3155</span><a name="line.3155"></a>
+<span class="sourceLineNo">3156</span>    protected final HRegion region;<a name="line.3156"></a>
+<span class="sourceLineNo">3157</span>    protected int nextIndexToProcess = 0;<a name="line.3157"></a>
+<span class="sourceLineNo">3158</span>    protected final ObservedExceptionsInBatch observedExceptions;<a name="line.3158"></a>
+<span class="sourceLineNo">3159</span>    //Durability of the batch (highest durability of all operations)<a name="line.3159"></a>
+<span class="sourceLineNo">3160</span>    protected Durability durability;<a name="line.3160"></a>
+<span class="sourceLineNo">3161</span>    protected boolean atomic = false;<a name="line.3161"></a>
+<span class="sourceLineNo">3162</span><a name="line.3162"></a>
+<span class="sourceLineNo">3163</span>    public BatchOperation(final HRegion region, T[] operations) {<a name="line.3163"></a>
+<span class="sourceLineNo">3164</span>      this.operations = operations;<a name="line.3164"></a>
+<span class="sourceLineNo">3165</span>      this.retCodeDetails = new OperationStatus[operations.length];<a name="line.3165"></a>
+<span class="sourceLineNo">3166</span>      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);<a name="line.3166"></a>
+<span class="sourceLineNo">3167</span>      this.walEditsFromCoprocessors = new WALEdit[operations.length];<a name="line.3167"></a>
+<span class="sourceLineNo">3168</span>      familyCellMaps = new Map[operations.length];<a name="line.3168"></a>
+<span class="sourceLineNo">3169</span><a name="line.3169"></a>
+<span class="sourceLineNo">3170</span>      this.region = region;<a name="line.3170"></a>
+<span class="sourceLineNo">3171</span>      observedExceptions = new ObservedExceptionsInBatch();<a name="line.3171"></a>
+<span class="sourceLineNo">3172</span>      durability = Durability.USE_DEFAULT;<a name="line.3172"></a>
+<span class="sourceLineNo">3173</span>    }<a name="line.3173"></a>
+<span class="sourceLineNo">3174</span><a name="line.3174"></a>
+<span class="sourceLineNo">3175</span>    /**<a name="line.3175"></a>
+<span class="sourceLineNo">3176</span>     * Visitor interface for batch operations<a name="line.3176"></a>
+<span class="sourceLineNo">3177</span>     */<a name="line.3177"></a>
+<span class="sourceLineNo">3178</span>    @FunctionalInterface<a name="line.3178"></a>
+<span class="sourceLineNo">3179</span>    public interface Visitor {<a name="line.3179"></a>
+<span class="sourceLineNo">3180</span>      /**<a name="line.3180"></a>
+<span class="sourceLineNo">3181</span>       * @param index operation index<a name="line.3181"></a>
+<span class="sourceLineNo">3182</span>       * @return If true continue visiting remaining entries, break otherwise<a name="line.3182"></a>
+<span class="sourceLineNo">3183</span>       */<a name="line.3183"></a>
+<span class="sourceLineNo">3184</span>      boolean visit(int index) throws IOException;<a name="line.3184"></a>
+<span class="sourceLineNo">3185</span>    }<a name="line.3185"></a>
+<span class="sourceLineNo">3186</span><a name="line.3186"></a>
+<span class="sourceLineNo">3187</span>    /**<a name="line.3187"></a>
+<span class="sourceLineNo">3188</span>     * Helper method for visiting pending/ all batch operations<a name="line.3188"></a>
+<span class="sourceLineNo">3189</span>     */<a name="line.3189"></a>
+<span class="sourceLineNo">3190</span>    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)<a name="line.3190"></a>
+<span class="sourceLineNo">3191</span>        throws IOException {<a name="line.3191"></a>
+<span class="sourceLineNo">3192</span>      assert lastIndexExclusive &lt;= this.size();<a name="line.3192"></a>
+<span class="sourceLineNo">3193</span>      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {<a name="line.3193"></a>
+<span class="sourceLineNo">3194</span>        if (!pendingOnly || isOperationPending(i)) {<a name="line.3194"></a>
+<span class="sourceLineNo">3195</span>          if (!visitor.visit(i)) {<a name="line.3195"></a>
+<span class="sourceLineNo">3196</span>            break;<a name="line.3196"></a>
+<span class="sourceLineNo">3197</span>          }<a name="line.3197"></a>
+<span class="sourceLineNo">3198</span>        }<a name="line.3198"></a>
+<span class="sourceLineNo">3199</span>      }<a name="line.3199"></a>
+<span class="sourceLineNo">3200</span>    }<a name="line.3200"></a>
+<span class="sourceLineNo">3201</span><a name="line.3201"></a>
+<span class="sourceLineNo">3202</span>    public abstract Mutation getMutation(int index);<a name="line.3202"></a>
+<span class="sourceLineNo">3203</span><a name="line.3203"></a>
+<span class="sourceLineNo">3204</span>    public abstract long getNonceGroup(int index);<a name="line.3204"></a>
+<span class="sourceLineNo">3205</span><a name="line.3205"></a>
+<span class="sourceLineNo">3206</span>    public abstract long getNonce(int index);<a name="line.3206"></a>
+<span class="sourceLineNo">3207</span><a name="line.3207"></a>
+<span class="sourceLineNo">3208</span>    /**<a name="line.3208"></a>
+<span class="sourceLineNo">3209</span>     * This method is potentially expensive and useful mostly for non-replay CP path.<a name="line.3209"></a>
+<span class="sourceLineNo">3210</span>     */<a name="line.3210"></a>
+<span class="sourceLineNo">3211</span>    public abstract Mutation[] getMutationsForCoprocs();<a name="line.3211"></a>
+<span class="sourceLineNo">3212</span><a name="line.3212"></a>
+<span class="sourceLineNo">3213</span>    public abstract boolean isInReplay();<a name="line.3213"></a>
+<span class="sourceLineNo">3214</span><a name="line.3214"></a>
+<span class="sourceLineNo">3215</span>    public abstract long getOrigLogSeqNum();<a name="line.3215"></a>
+<span class="sourceLineNo">3216</span><a name="line.3216"></a>
+<span class="sourceLineNo">3217</span>    public abstract void startRegionOperation() throws IOException;<a name="line.3217"></a>
+<span class="sourceLineNo">3218</span><a name="line.3218"></a>
+<span class="sourceLineNo">3219</span>    public abstract void closeRegionOperation() throws IOException;<a name="line.3219"></a>
+<span class="sourceLineNo">3220</span><a name="line.3220"></a>
+<span class="sourceLineNo">3221</span>    /**<a name="line.3221"></a>
+<span class="sourceLineNo">3222</span>     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs<a name="line.3222"></a>
+<span class="sourceLineNo">3223</span>     * CP prePut()/ preDelete() hooks for all mutations in a batch. This is intended to operate on<a name="line.3223"></a>
+<span class="sourceLineNo">3224</span>     * entire batch and will be called from outside of class to check and prepare batch. This can<a name="line.3224"></a>
+<span class="sourceLineNo">3225</span>     * be implemented by calling helper method {@link #checkAndPrepareMutation(int, long)} in a<a name="line.3225"></a>
+<span class="sourceLineNo">3226</span>     * 'for' loop over mutations.<a name="line.3226"></a>
+<span class="sourceLineNo">3227</span>     */<a name="line.3227"></a>
+<span class="sourceLineNo">3228</span>    public abstract void checkAndPrepare() throws IOException;<a name="line.3228"></a>
+<span class="sourceLineNo">3229</span><a name="line.3229"></a>
+<span class="sourceLineNo">3230</span>    /**<a name="line.3230"></a>
+<span class="sourceLineNo">3231</span>     * Implement any Put request specific check and prepare logic here. Please refer to<a name="line.3231"></a>
+<span class="sourceLineNo">3232</span>     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.<a name="line.3232"></a>
+<span class="sourceLineNo">3233</span>     */<a name="line.3233"></a>
+<span class="sourceLineNo">3234</span>    protected abstract void checkAndPreparePut(final Put p) throws IOException;<a name="line.3234"></a>
+<span class="sourceLineNo">3235</span><a name="line.3235"></a>
+<span class="sourceLineNo">3236</span>    /**<a name="line.3236"></a>
+<span class="sourceLineNo">3237</span>     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell<a name="line.3237"></a>
+<span class="sourceLineNo">3238</span>     * count, tags and timestamp for all cells of all operations in a mini-batch.<a name="line.3238"></a>
+<span class="sourceLineNo">3239</span>     */<a name="line.3239"></a>
+<span class="sourceLineNo">3240</span>    public abstract void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3240"></a>
+<span class="sourceLineNo">3241</span>        miniBatchOp, long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;<a name="line.3241"></a>
+<span class="sourceLineNo">3242</span><a name="line.3242"></a>
+<span class="sourceLineNo">3243</span>    /**<a name="line.3243"></a>
+<span class="sourceLineNo">3244</span>     * Write mini-batch operations to MemStore<a name="line.3244"></a>
+<span class="sourceLineNo">3245</span>     */<a name="line.3245"></a>
+<span class="sourceLineNo">3246</span>    public abstract WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3246"></a>
+<span class="sourceLineNo">3247</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3247"></a>
+<span class="sourceLineNo">3248</span>        throws IOException;<a name="line.3248"></a>
+<span class="sourceLineNo">3249</span><a name="line.3249"></a>
+<span class="sourceLineNo">3250</span>    protected void writeMiniBatchOperationsToMemStore(<a name="line.3250"></a>
+<span class="sourceLineNo">3251</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)<a name="line.3251"></a>
+<span class="sourceLineNo">3252</span>        throws IOException {<a name="line.3252"></a>
+<span class="sourceLineNo">3253</span>      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.3253"></a>
+<span class="sourceLineNo">3254</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3254"></a>
+<span class="sourceLineNo">3255</span>        // We need to update the sequence id for following reasons.<a name="line.3255"></a>
+<span class="sourceLineNo">3256</span>        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.<a name="line.3256"></a>
+<span class="sourceLineNo">3257</span>        // 2) If no WAL, FSWALEntry won't be used<a name="line.3257"></a>
+<span class="sourceLineNo">3258</span>        // we use durability of the original mutation for the mutation passed by CP.<a name="line.3258"></a>
+<span class="sourceLineNo">3259</span>        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {<a name="line.3259"></a>
+<span class="sourceLineNo">3260</span>          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);<a name="line.3260"></a>
+<span class="sourceLineNo">3261</span>        }<a name="line.3261"></a>
+<span class="sourceLineNo">3262</span>        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);<a name="line.3262"></a>
+<span class="sourceLineNo">3263</span>        return true;<a name="line.3263"></a>
+<span class="sourceLineNo">3264</span>      });<a name="line.3264"></a>
+<span class="sourceLineNo">3265</span>      // update memStore size<a name="line.3265"></a>
+<span class="sourceLineNo">3266</span>      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),<a name="line.3266"></a>
+<span class="sourceLineNo">3267</span>        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());<a name="line.3267"></a>
+<span class="sourceLineNo">3268</span>    }<a name="line.3268"></a>
+<span class="sourceLineNo">3269</span><a name="line.3269"></a>
+<span class="sourceLineNo">3270</span>    public boolean isDone() {<a name="line.3270"></a>
+<span class="sourceLineNo">3271</span>      return nextIndexToProcess == operations.length;<a name="line.3271"></a>
+<span class="sourceLineNo">3272</span>    }<a name="line.3272"></a>
+<span class="sourceLineNo">3273</span><a name="line.3273"></a>
+<span class="sourceLineNo">3274</span>    public int size() {<a name="line.3274"></a>
+<span class="sourceLineNo">3275</span>      return operations.length;<a name="line.3275"></a>
+<span class="sourceLineNo">3276</span>    }<a name="line.3276"></a>
+<span class="sourceLineNo">3277</span><a name="line.3277"></a>
+<span class="sourceLineNo">3278</span>    public boolean isOperationPending(int index) {<a name="line.3278"></a>
+<span class="sourceLineNo">3279</span>      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;<a name="line.3279"></a>
+<span class="sourceLineNo">3280</span>    }<a name="line.3280"></a>
+<span class="sourceLineNo">3281</span><a name="line.3281"></a>
+<span class="sourceLineNo">3282</span>    public List&lt;UUID&gt; getClusterIds() {<a name="line.3282"></a>
+<span class="sourceLineNo">3283</span>      assert size() != 0;<a name="line.3283"></a>
+<span class="sourceLineNo">3284</span>      return getMutation(0).getClusterIds();<a name="line.3284"></a>
+<span class="sourceLineNo">3285</span>    }<a name="line.3285"></a>
+<span class="sourceLineNo">3286</span><a name="line.3286"></a>
+<span class="sourceLineNo">3287</span>    boolean isAtomic() {<a name="line.3287"></a>
+<span class="sourceLineNo">3288</span>      return atomic;<a name="line.3288"></a>
+<span class="sourceLineNo">3289</span>    }<a name="line.3289"></a>
+<span class="sourceLineNo">3290</span><a name="line.3290"></a>
+<span class="sourceLineNo">3291</span>    /**<a name="line.3291"></a>
+<span class="sourceLineNo">3292</span>     * Helper method that checks and prepares only one mutation. This can be used to implement<a name="line.3292"></a>
+<span class="sourceLineNo">3293</span>     * {@link #checkAndPrepare()} for entire Batch.<a name="line.3293"></a>
+<span class="sourceLineNo">3294</span>     * NOTE: As CP prePut()/ preDelete() hooks may modify mutations, this method should be called<a name="line.3294"></a>
+<span class="sourceLineNo">3295</span>     * after prePut()/ preDelete() CP hooks are run for the mutation<a name="line.3295"></a>
+<span class="sourceLineNo">3296</span>     */<a name="line.3296"></a>
+<span class="sourceLineNo">3297</span>    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)<a name="line.3297"></a>
+<span class="sourceLineNo">3298</span>        throws IOException {<a name="line.3298"></a>
+<span class="sourceLineNo">3299</span>      region.checkRow(mutation.getRow(), "batchMutate");<a name="line.3299"></a>
+<span class="sourceLineNo">3300</span>      if (mutation instanceof Put) {<a name="line.3300"></a>
+<span class="sourceLineNo">3301</span>        // Check the families in the put. If bad, skip this one.<a name="line.3301"></a>
+<span class="sourceLineNo">3302</span>        checkAndPreparePut((Put) mutation);<a name="line.3302"></a>
+<span class="sourceLineNo">3303</span>        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);<a name="line.3303"></a>
+<span class="sourceLineNo">3304</span>      } else {<a name="line.3304"></a>
+<span class="sourceLineNo">3305</span>        region.prepareDelete((Delete) mutation);<a name="line.3305"></a>
+<span class="sourceLineNo">3306</span>      }<a name="line.3306"></a>
+<span class="sourceLineNo">3307</span>    }<a name="line.3307"></a>
+<span class="sourceLineNo">3308</span><a name="line.3308"></a>
+<span class="sourceLineNo">3309</span>    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {<a name="line.3309"></a>
+<span class="sourceLineNo">3310</span>      Mutation mutation = getMutation(index);<a name="line.3310"></a>
+<span class="sourceLineNo">3311</span>      try {<a name="line.3311"></a>
+<span class="sourceLineNo">3312</span>        this.checkAndPrepareMutation(mutation, timestamp);<a name="line.3312"></a>
+<span class="sourceLineNo">3313</span><a name="line.3313"></a>
+<span class="sourceLineNo">3314</span>        // store the family map reference to allow for mutations<a name="line.3314"></a>
+<span class="sourceLineNo">3315</span>        familyCellMaps[index] = mutation.getFamilyCellMap();<a name="line.3315"></a>
+<span class="sourceLineNo">3316</span>        // store durability for the batch (highest durability of all operations in the batch)<a name="line.3316"></a>
+<span class="sourceLineNo">3317</span>        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());<a name="line.3317"></a>
+<span class="sourceLineNo">3318</span>        if (tmpDur.ordinal() &gt; durability.ordinal()) {<a name="line.3318"></a>
+<span class="sourceLineNo">3319</span>          durability = tmpDur;<a name="line.3319"></a>
+<span class="sourceLineNo">3320</span>        }<a name="line.3320"></a>
+<span class="sourceLineNo">3321</span>      } catch (NoSuchColumnFamilyException nscfe) {<a name="line.3321"></a>
+<span class="sourceLineNo">3322</span>        final String msg = "No such column family in batch mutation. ";<a name="line.3322"></a>
+<span class="sourceLineNo">3323</span>        if (observedExceptions.hasSeenNoSuchFamily()) {<a name="line.3323"></a>
+<span class="sourceLineNo">3324</span>          LOG.warn(msg + nscfe.getMessage());<a name="line.3324"></a>
+<span class="sourceLineNo">3325</span>        } else {<a name="line.3325"></a>
+<span class="sourceLineNo">3326</span>          LOG.warn(msg, nscfe);<a name="line.3326"></a>
+<span class="sourceLineNo">3327</span>          observedExceptions.sawNoSuchFamily();<a name="line.3327"></a>
+<span class="sourceLineNo">3328</span>        }<a name="line.3328"></a>
+<span class="sourceLineNo">3329</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3329"></a>
+<span class="sourceLineNo">3330</span>            OperationStatusCode.BAD_FAMILY, nscfe.getMessage());<a name="line.3330"></a>
+<span class="sourceLineNo">3331</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3331"></a>
+<span class="sourceLineNo">3332</span>          throw nscfe;<a name="line.3332"></a>
+<span class="sourceLineNo">3333</span>        }<a name="line.3333"></a>
+<span class="sourceLineNo">3334</span>      } catch (FailedSanityCheckException fsce) {<a name="line.3334"></a>
+<span class="sourceLineNo">3335</span>        final String msg = "Batch Mutation did not pass sanity check. ";<a name="line.3335"></a>
+<span class="sourceLineNo">3336</span>        if (observedExceptions.hasSeenFailedSanityCheck()) {<a name="line.3336"></a>
+<span class="sourceLineNo">3337</span>          LOG.warn(msg + fsce.getMessage());<a name="line.3337"></a>
+<span class="sourceLineNo">3338</span>        } else {<a name="line.3338"></a>
+<span class="sourceLineNo">3339</span>          LOG.warn(msg, fsce);<a name="line.3339"></a>
+<span class="sourceLineNo">3340</span>          observedExceptions.sawFailedSanityCheck();<a name="line.3340"></a>
+<span class="sourceLineNo">3341</span>        }<a name="line.3341"></a>
+<span class="sourceLineNo">3342</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3342"></a>
+<span class="sourceLineNo">3343</span>            OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());<a name="line.3343"></a>
+<span class="sourceLineNo">3344</span>        if (isAtomic()) {<a name="line.3344"></a>
+<span class="sourceLineNo">3345</span>          throw fsce;<a name="line.3345"></a>
+<span class="sourceLineNo">3346</span>        }<a name="line.3346"></a>
+<span class="sourceLineNo">3347</span>      } catch (WrongRegionException we) {<a name="line.3347"></a>
+<span class="sourceLineNo">3348</span>        final String msg = "Batch mutation had a row that does not belong to this region. ";<a name="line.3348"></a>
+<span class="sourceLineNo">3349</span>        if (observedExceptions.hasSeenWrongRegion()) {<a name="line.3349"></a>
+<span class="sourceLineNo">3350</span>          LOG.warn(msg + we.getMessage());<a name="line.3350"></a>
+<span class="sourceLineNo">3351</span>        } else {<a name="line.3351"></a>
+<span class="sourceLineNo">3352</span>          LOG.warn(msg, we);<a name="line.3352"></a>
+<span class="sourceLineNo">3353</span>          observedExceptions.sawWrongRegion();<a name="line.3353"></a>
+<span class="sourceLineNo">3354</span>        }<a name="line.3354"></a>
+<span class="sourceLineNo">3355</span>        retCodeDetails[index] = new OperationStatus(<a name="line.3355"></a>
+<span class="sourceLineNo">3356</span>            OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());<a name="line.3356"></a>
+<span class="sourceLineNo">3357</span>        if (isAtomic()) {<a name="line.3357"></a>
+<span class="sourceLineNo">3358</span>          throw we;<a name="line.3358"></a>
+<span class="sourceLineNo">3359</span>        }<a name="line.3359"></a>
+<span class="sourceLineNo">3360</span>      }<a name="line.3360"></a>
+<span class="sourceLineNo">3361</span>    }<a name="line.3361"></a>
+<span class="sourceLineNo">3362</span><a name="line.3362"></a>
+<span class="sourceLineNo">3363</span>    /**<a name="line.3363"></a>
+<span class="sourceLineNo">3364</span>     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which<a name="line.3364"></a>
+<span class="sourceLineNo">3365</span>     * a row lock can be acquired. All mutations with locked rows are considered to be<a name="line.3365"></a>
+<span class="sourceLineNo">3366</span>     * In-progress operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch<a name="line.3366"></a>
+<span class="sourceLineNo">3367</span>     * is window over {@link BatchOperation} and contains contiguous pending operations.<a name="line.3367"></a>
+<span class="sourceLineNo">3368</span>     *<a name="line.3368"></a>
+<span class="sourceLineNo">3369</span>     * @param acquiredRowLocks keeps track of rowLocks acquired.<a name="line.3369"></a>
+<span class="sourceLineNo">3370</span>     */<a name="line.3370"></a>
+<span class="sourceLineNo">3371</span>    public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.3371"></a>
+<span class="sourceLineNo">3372</span>        List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3372"></a>
+<span class="sourceLineNo">3373</span>      int readyToWriteCount = 0;<a name="line.3373"></a>
+<span class="sourceLineNo">3374</span>      int lastIndexExclusive = 0;<a name="line.3374"></a>
+<span class="sourceLineNo">3375</span>      RowLock prevRowLock = null;<a name="line.3375"></a>
+<span class="sourceLineNo">3376</span>      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {<a name="line.3376"></a>
+<span class="sourceLineNo">3377</span>        // It reaches the miniBatchSize, stop here and process the miniBatch<a name="line.3377"></a>
+<span class="sourceLineNo">3378</span>        // This only applies to non-atomic batch operations.<a name="line.3378"></a>
+<span class="sourceLineNo">3379</span>        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {<a name="line.3379"></a>
+<span class="sourceLineNo">3380</span>          break;<a name="line.3380"></a>
+<span class="sourceLineNo">3381</span>        }<a name="line.3381"></a>
+<span class="sourceLineNo">3382</span><a name="line.3382"></a>
+<span class="sourceLineNo">3383</span>        if (!isOperationPending(lastIndexExclusive)) {<a name="line.3383"></a>
+<span class="sourceLineNo">3384</span>          continue;<a name="line.3384"></a>
+<span class="sourceLineNo">3385</span>        }<a name="line.3385"></a>
+<span class="sourceLineNo">3386</span><a name="line.3386"></a>
+<span class="sourceLineNo">3387</span>        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting<a name="line.3387"></a>
+<span class="sourceLineNo">3388</span>        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation<a name="line.3388"></a>
+<span class="sourceLineNo">3389</span>        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't<a name="line.3389"></a>
+<span class="sourceLineNo">3390</span>        // pass the isOperationPending check<a name="line.3390"></a>
+<span class="sourceLineNo">3391</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =<a name="line.3391"></a>
+<span class="sourceLineNo">3392</span>            getMutation(lastIndexExclusive).getFamilyCellMap();<a name="line.3392"></a>
+<span class="sourceLineNo">3393</span>        try {<a name="line.3393"></a>
+<span class="sourceLineNo">3394</span>          // start the protector before acquiring row lock considering performance, and will finish<a name="line.3394"></a>
+<span class="sourceLineNo">3395</span>          // it when encountering exception<a name="line.3395"></a>
+<span class="sourceLineNo">3396</span>          region.storeHotnessProtector.start(curFamilyCellMap);<a name="line.3396"></a>
+<span class="sourceLineNo">3397</span>        } catch (RegionTooBusyException rtbe) {<a name="line.3397"></a>
+<span class="sourceLineNo">3398</span>          region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3398"></a>
+<span class="sourceLineNo">3399</span>          if (isAtomic()) {<a name="line.3399"></a>
+<span class="sourceLineNo">3400</span>            throw rtbe;<a name="line.3400"></a>
+<span class="sourceLineNo">3401</span>          }<a name="line.3401"></a>
+<span class="sourceLineNo">3402</span>          retCodeDetails[lastIndexExclusive] =<a name="line.3402"></a>
+<span class="sourceLineNo">3403</span>              new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());<a name="line.3403"></a>
+<span class="sourceLineNo">3404</span>          continue;<a name="line.3404"></a>
+<span class="sourceLineNo">3405</span>        }<a name="line.3405"></a>
+<span class="sourceLineNo">3406</span><a name="line.3406"></a>
+<span class="sourceLineNo">3407</span>        Mutation mutation = getMutation(lastIndexExclusive);<a name="line.3407"></a>
+<span class="sourceLineNo">3408</span>        // If we haven't got any rows in our batch, we should block to get the next one.<a name="line.3408"></a>
+<span class="sourceLineNo">3409</span>        RowLock rowLock = null;<a name="line.3409"></a>
+<span class="sourceLineNo">3410</span>        boolean throwException = false;<a name="line.3410"></a>
+<span class="sourceLineNo">3411</span>        try {<a name="line.3411"></a>
+<span class="sourceLineNo">3412</span>          // if atomic then get exclusive lock, else shared lock<a name="line.3412"></a>
+<span class="sourceLineNo">3413</span>          rowLock = region.getRowLockInternal(mutation.getRow(), !isAtomic(), prevRowLock);<a name="line.3413"></a>
+<span class="sourceLineNo">3414</span>        } catch (TimeoutIOException | InterruptedIOException e) {<a name="line.3414"></a>
+<span class="sourceLineNo">3415</span>          // NOTE: We will retry when other exceptions, but we should stop if we receive<a name="line.3415"></a>
+<span class="sourceLineNo">3416</span>          // TimeoutIOException or InterruptedIOException as operation has timed out or<a name="line.3416"></a>
+<span class="sourceLineNo">3417</span>          // interrupted respectively.<a name="line.3417"></a>
+<span class="sourceLineNo">3418</span>          throwException = true;<a name="line.3418"></a>
+<span class="sourceLineNo">3419</span>          throw e;<a name="line.3419"></a>
+<span class="sourceLineNo">3420</span>        } catch (IOException ioe) {<a name="line.3420"></a>
+<span class="sourceLineNo">3421</span>          LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(mutation.getRow()), ioe);<a name="line.3421"></a>
+<span class="sourceLineNo">3422</span>          if (isAtomic()) { // fail, atomic means all or none<a name="line.3422"></a>
+<span class="sourceLineNo">3423</span>            throwException = true;<a name="line.3423"></a>
+<span class="sourceLineNo">3424</span>            throw ioe;<a name="line.3424"></a>
+<span class="sourceLineNo">3425</span>          }<a name="line.3425"></a>
+<span class="sourceLineNo">3426</span>        } catch (Throwable throwable) {<a name="line.3426"></a>
+<span class="sourceLineNo">3427</span>          throwException = true;<a name="line.3427"></a>
+<span class="sourceLineNo">3428</span>          throw throwable;<a name="line.3428"></a>
+<span class="sourceLineNo">3429</span>        } finally {<a name="line.3429"></a>
+<span class="sourceLineNo">3430</span>          if (throwException) {<a name="line.3430"></a>
+<span class="sourceLineNo">3431</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3431"></a>
+<span class="sourceLineNo">3432</span>          }<a name="line.3432"></a>
+<span class="sourceLineNo">3433</span>        }<a name="line.3433"></a>
+<span class="sourceLineNo">3434</span>        if (rowLock == null) {<a name="line.3434"></a>
+<span class="sourceLineNo">3435</span>          // We failed to grab another lock<a name="line.3435"></a>
+<span class="sourceLineNo">3436</span>          if (isAtomic()) {<a name="line.3436"></a>
+<span class="sourceLineNo">3437</span>            region.storeHotnessProtector.finish(curFamilyCellMap);<a name="line.3437"></a>
+<span class="sourceLineNo">3438</span>            throw new IOException("Can't apply all operations atomically!");<a name="line.3438"></a>
+<span class="sourceLineNo">3439</span>          }<a name="line.3439"></a>
+<span class="sourceLineNo">3440</span>          break; // Stop acquiring more rows for this batch<a name="line.3440"></a>
+<span class="sourceLineNo">3441</span>        } else {<a name="line.3441"></a>
+<span class="sourceLineNo">3442</span>          if (rowLock != prevRowLock) {<a name="line.3442"></a>
+<span class="sourceLineNo">3443</span>            // It is a different row now, add this to the acquiredRowLocks and<a name="line.3443"></a>
+<span class="sourceLineNo">3444</span>            // set prevRowLock to the new returned rowLock<a name="line.3444"></a>
+<span class="sourceLineNo">3445</span>            acquiredRowLocks.add(rowLock);<a name="line.3445"></a>
+<span class="sourceLineNo">3446</span>            prevRowLock = rowLock;<a name="line.3446"></a>
+<span class="sourceLineNo">3447</span>          }<a name="line.3447"></a>
+<span class="sourceLineNo">3448</span>        }<a name="line.3448"></a>
+<span class="sourceLineNo">3449</span><a name="line.3449"></a>
+<span class="sourceLineNo">3450</span>        readyToWriteCount++;<a name="line.3450"></a>
+<span class="sourceLineNo">3451</span>      }<a name="line.3451"></a>
+<span class="sourceLineNo">3452</span>      return createMiniBatch(lastIndexExclusive, readyToWriteCount);<a name="line.3452"></a>
+<span class="sourceLineNo">3453</span>    }<a name="line.3453"></a>
+<span class="sourceLineNo">3454</span><a name="line.3454"></a>
+<span class="sourceLineNo">3455</span>    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,<a name="line.3455"></a>
+<span class="sourceLineNo">3456</span>        final int readyToWriteCount) {<a name="line.3456"></a>
+<span class="sourceLineNo">3457</span>      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,<a name="line.3457"></a>
+<span class="sourceLineNo">3458</span>          walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);<a name="line.3458"></a>
+<span class="sourceLineNo">3459</span>    }<a name="line.3459"></a>
+<span class="sourceLineNo">3460</span><a name="line.3460"></a>
+<span class="sourceLineNo">3461</span>    /**<a name="line.3461"></a>
+<span class="sourceLineNo">3462</span>     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are<a name="line.3462"></a>
+<span class="sourceLineNo">3463</span>     * present, they are merged to result WALEdit.<a name="line.3463"></a>
+<span class="sourceLineNo">3464</span>     */<a name="line.3464"></a>
+<span class="sourceLineNo">3465</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(<a name="line.3465"></a>
+<span class="sourceLineNo">3466</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {<a name="line.3466"></a>
+<span class="sourceLineNo">3467</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();<a name="line.3467"></a>
 <span class="sourceLineNo">3468</span><a name="line.3468"></a>
-<span class="sourceLineNo">3469</span>        @Override<a name="line.3469"></a>
-<span class="sourceLineNo">3470</span>        public boolean visit(int index) throws IOException {<a name="line.3470"></a>
-<span class="sourceLineNo">3471</span>          Mutation m = getMutation(index);<a name="line.3471"></a>
-<span class="sourceLineNo">3472</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3472"></a>
-<span class="sourceLineNo">3473</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3473"></a>
-<span class="sourceLineNo">3474</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3474"></a>
-<span class="sourceLineNo">3475</span>            return true;<a name="line.3475"></a>
-<span class="sourceLineNo">3476</span>          }<a name="line.3476"></a>
-<span class="sourceLineNo">3477</span><a name="line.3477"></a>
-<span class="sourceLineNo">3478</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3478"></a>
-<span class="sourceLineNo">3479</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3479"></a>
-<span class="sourceLineNo">3480</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3480"></a>
-<span class="sourceLineNo">3481</span>          long nonceGroup = getNonceGroup(index);<a name="line.3481"></a>
-<span class="sourceLineNo">3482</span>          long nonce = getNonce(index);<a name="line.3482"></a>
-<span class="sourceLineNo">3483</span>          if (curWALEditForNonce == null ||<a name="line.3483"></a>
-<span class="sourceLineNo">3484</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3484"></a>
-<span class="sourceLineNo">3485</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3485"></a>
-<span class="sourceLineNo">3486</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3486"></a>
-<span class="sourceLineNo">3487</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3487"></a>
-<span class="sourceLineNo">3488</span>            walEdits.add(curWALEditForNonce);<a name="line.3488"></a>
-<span class="sourceLineNo">3489</span>          }<a name="line.3489"></a>
-<span class="sourceLineNo">3490</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3490"></a>
-<span class="sourceLineNo">3491</span><a name="line.3491"></a>
-<span class="sourceLineNo">3492</span>          // Add WAL edits from CPs.<a name="line.3492"></a>
-<span class="sourceLineNo">3493</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3493"></a>
-<span class="sourceLineNo">3494</span>          if (fromCP != null) {<a name="line.3494"></a>
-<span class="sourceLineNo">3495</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3495"></a>
-<span class="sourceLineNo">3496</span>              walEdit.add(cell);<a name="line.3496"></a>
-<span class="sourceLineNo">3497</span>            }<a name="line.3497"></a>
-<span class="sourceLineNo">3498</span>          }<a name="line.3498"></a>
-<span class="sourceLineNo">3499</span>          walEdit.add(familyCellMaps[index]);<a name="line.3499"></a>
-<span class="sourceLineNo">3500</span><a name="line.3500"></a>
-<span class="sourceLineNo">3501</span>          return true;<a name="line.3501"></a>
-<span class="sourceLineNo">3502</span>        }<a name="line.3502"></a>
-<span class="sourceLineNo">3503</span>      });<a name="line.3503"></a>
-<span class="sourceLineNo">3504</span>      return walEdits;<a name="line.3504"></a>
-<span class="sourceLineNo">3505</span>    }<a name="line.3505"></a>
-<span class="sourceLineNo">3506</span><a name="line.3506"></a>
-<span class="sourceLineNo">3507</span>    /**<a name="line.3507"></a>
-<span class="sourceLineNo">3508</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3508"></a>
-<span class="sourceLineNo">3509</span>     * required) and completing mvcc.<a name="line.3509"></a>
-<span class="sourceLineNo">3510</span>     */<a name="line.3510"></a>
-<span class="sourceLineNo">3511</span>    public void completeMiniBatchOperations(<a name="line.3511"></a>
-<span class="sourceLineNo">3512</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3512"></a>
-<span class="sourceLineNo">3513</span>        throws IOException {<a name="line.3513"></a>
-<span class="sourceLineNo">3514</span>      if (writeEntry != null) {<a name="line.3514"></a>
-<span class="sourceLineNo">3515</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3515"></a>
-<span class="sourceLineNo">3516</span>      }<a name="line.3516"></a>
-<span class="sourceLineNo">3517</span>    }<a name="line.3517"></a>
-<span class="sourceLineNo">3518</span><a name="line.3518"></a>
-<span class="sourceLineNo">3519</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3519"></a>
-<span class="sourceLineNo">3520</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3520"></a>
-<span class="sourceLineNo">3521</span>        boolean success) throws IOException {<a name="line.3521"></a>
-<span class="sourceLineNo">3522</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3522"></a>
-<span class="sourceLineNo">3523</span>    }<a name="line.3523"></a>
-<span class="sourceLineNo">3524</span><a name="line.3524"></a>
-<span class="sourceLineNo">3525</span>    private void doFinishHotnessProtector(<a name="line.3525"></a>
-<span class="sourceLineNo">3526</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3526"></a>
-<span class="sourceLineNo">3527</span>      // check and return if the protector is not enabled<a name="line.3527"></a>
-<span class="sourceLineNo">3528</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3528"></a>
-<span class="sourceLineNo">3529</span>        return;<a name="line.3529"></a>
-<span class="sourceLineNo">3530</span>      }<a name="line.3530"></a>
-<span class="sourceLineNo">3531</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3531"></a>
-<span class="sourceLineNo">3532</span>      // This case was handled.<a name="line.3532"></a>
-<span class="sourceLineNo">3533</span>      if (miniBatchOp == null) {<a name="line.3533"></a>
-<span class="sourceLineNo">3534</span>        return;<a name="line.3534"></a>
-<span class="sourceLineNo">3535</span>      }<a name="line.3535"></a>
-<span class="sourceLineNo">3536</span><a name="line.3536"></a>
-<span class="sourceLineNo">3537</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3537"></a>
-<span class="sourceLineNo">3538</span><a name="line.3538"></a>
-<span class="sourceLineNo">3539</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3539"></a>
-<span class="sourceLineNo">3540</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3540"></a>
-<span class="sourceLineNo">3541</span>          case SUCCESS:<a name="line.3541"></a>
-<span class="sourceLineNo">3542</span>          case FAILURE:<a name="line.3542"></a>
-<span class="sourceLineNo">3543</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3543"></a>
-<span class="sourceLineNo">3544</span>            break;<a name="line.3544"></a>
-<span class="sourceLineNo">3545</span>          default:<a name="line.3545"></a>
-<span class="sourceLineNo">3546</span>            // do nothing<a name="line.3546"></a>
-<span class="sourceLineNo">3547</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3547"></a>
-<span class="sourceLineNo">3548</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3548"></a>
-<span class="sourceLineNo">3549</span>            break;<a name="line.3549"></a>
-<span class="sourceLineNo">3550</span>        }<a name="line.3550"></a>
-<span class="sourceLineNo">3551</span>      }<a name="line.3551"></a>
-<span class="sourceLineNo">3552</span>    }<a name="line.3552"></a>
-<span class="sourceLineNo">3553</span><a name="line.3553"></a>
-<span class="sourceLineNo">3554</span>    /**<a name="line.3554"></a>
-<span class="sourceLineNo">3555</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3555"></a>
-<span class="sourceLineNo">3556</span>     * This handles the consistency control on its own, but the caller<a name="line.3556"></a>
-<span class="sourceLineNo">3557</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3557"></a>
-<span class="sourceLineNo">3558</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3558"></a>
-<span class="sourceLineNo">3559</span>     *<a name="line.3559"></a>
-<span class="sourceLineNo">3560</span>     * @param familyMap Map of Cells by family<a name="line.3560"></a>
-<span class="sourceLineNo">3561</span>     */<a name="line.3561"></a>
-<span class="sourceLineNo">3562</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3562"></a>
-<span class="sourceLineNo">3563</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3563"></a>
-<span class="sourceLineNo">3564</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3564"></a>
-<span class="sourceLineNo">3565</span>        byte[] family = e.getKey();<a name="line.3565"></a>
-<span class="sourceLineNo">3566</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3566"></a>
-<span class="sourceLineNo">3567</span>        assert cells instanceof RandomAccess;<a name="line.3567"></a>
-<span class="sourceLineNo">3568</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3568"></a>
-<span class="sourceLineNo">3569</span>      }<a name="line.3569"></a>
-<span class="sourceLineNo">3570</span>    }<a name="line.3570"></a>
-<span class="sourceLineNo">3571</span>  }<a name="line.3571"></a>
-<span class="sourceLineNo">3572</span><a name="line.3572"></a>
-<span class="sourceLineNo">3573</span><a name="line.3573"></a>
-<span class="sourceLineNo">3574</span>  /**<a name="line.3574"></a>
-<span class="sourceLineNo">3575</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3575"></a>
-<span class="sourceLineNo">3576</span>   * of the logic is same.<a name="line.3576"></a>
-<span class="sourceLineNo">3577</span>   */<a name="line.3577"></a>
-<span class="sourceLineNo">3578</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3578"></a>
-<span class="sourceLineNo">3579</span>    private long nonceGroup;<a name="line.3579"></a>
-<span class="sourceLineNo">3580</span>    private long nonce;<a name="line.3580"></a>
-<span class="sourceLineNo">3581</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3581"></a>
-<span class="sourceLineNo">3582</span>        long nonceGroup, long nonce) {<a name="line.3582"></a>
-<span class="sourceLineNo">3583</span>      super(region, operations);<a name="line.3583"></a>
-<span class="sourceLineNo">3584</span>      this.atomic = atomic;<a name="line.3584"></a>
-<span class="sourceLineNo">3585</span>      this.nonceGroup = nonceGroup;<a name="line.3585"></a>
-<span class="sourceLineNo">3586</span>      this.nonce = nonce;<a name="line.3586"></a>
-<span class="sourceLineNo">3587</span>    }<a name="line.3587"></a>
-<span class="sourceLineNo">3588</span><a name="line.3588"></a>
-<span class="sourceLineNo">3589</span>    @Override<a name="line.3589"></a>
-<span class="sourceLineNo">3590</span>    public Mutation getMutation(int index) {<a name="line.3590"></a>
-<span class="sourceLineNo">3591</span>      return this.operations[index];<a name="line.3591"></a>
-<span class="sourceLineNo">3592</span>    }<a name="line.3592"></a>
-<span class="sourceLineNo">3593</span><a name="line.3593"></a>
-<span class="sourceLineNo">3594</span>    @Override<a name="line.3594"></a>
-<span class="sourceLineNo">3595</span>    public long getNonceGroup(int index) {<a name="line.3595"></a>
-<span class="sourceLineNo">3596</span>      return nonceGroup;<a name="line.3596"></a>
-<span class="sourceLineNo">3597</span>    }<a name="line.3597"></a>
-<span class="sourceLineNo">3598</span><a name="line.3598"></a>
-<span class="sourceLineNo">3599</span>    @Override<a name="line.3599"></a>
-<span class="sourceLineNo">3600</span>    public long getNonce(int index) {<a name="line.3600"></a>
-<span class="sourceLineNo">3601</span>      return nonce;<a name="line.3601"></a>
-<span class="sourceLineNo">3602</span>    }<a name="line.3602"></a>
-<span class="sourceLineNo">3603</span><a name="line.3603"></a>
-<span class="sourceLineNo">3604</span>    @Override<a name="line.3604"></a>
-<span class="sourceLineNo">3605</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3605"></a>
-<span class="sourceLineNo">3606</span>      return this.operations;<a name="line.3606"></a>
-<span class="sourceLineNo">3607</span>    }<a name="line.3607"></a>
-<span class="sourceLineNo">3608</span><a name="line.3608"></a>
-<span class="sourceLineNo">3609</span>    @Override<a name="line.3609"></a>
-<span class="sourceLineNo">3610</span>    public boolean isInReplay() {<a name="line.3610"></a>
-<span class="sourceLineNo">3611</span>      return false;<a name="line.3611"></a>
-<span class="sourceLineNo">3612</span>    }<a name="line.3612"></a>
-<span class="sourceLineNo">3613</span><a name="line.3613"></a>
-<span class="sourceLineNo">3614</span>    @Override<a name="line.3614"></a>
-<span class="sourceLineNo">3615</span>    public long getOrigLogSeqNum() {<a name="line.3615"></a>
-<span class="sourceLineNo">3616</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3616"></a>
-<span class="sourceLineNo">3617</span>    }<a name="line.3617"></a>
-<span class="sourceLineNo">3618</span><a name="line.3618"></a>
-<span class="sourceLineNo">3619</span>    @Override<a name="line.3619"></a>
-<span class="sourceLineNo">3620</span>    public void startRegionOperation() throws IOException {<a name="line.3620"></a>
-<span class="sourceLineNo">3621</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3621"></a>
-<span class="sourceLineNo">3622</span>    }<a name="line.3622"></a>
-<span class="sourceLineNo">3623</span><a name="line.3623"></a>
-<span class="sourceLineNo">3624</span>    @Override<a name="line.3624"></a>
-<span class="sourceLineNo">3625</span>    public void closeRegionOperation() throws IOException {<a name="line.3625"></a>
-<span class="sourceLineNo">3626</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3626"></a>
-<span class="sourceLineNo">3627</span>    }<a name="line.3627"></a>
-<span class="sourceLineNo">3628</span><a name="line.3628"></a>
-<span class="sourceLineNo">3629</span>    @Override<a name="line.3629"></a>
-<span class="sourceLineNo">3630</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3630"></a>
-<span class="sourceLineNo">3631</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3631"></a>
-<span class="sourceLineNo">3632</span>    }<a name="line.3632"></a>
-<span class="sourceLineNo">3633</span><a name="line.3633"></a>
-<span class="sourceLineNo">3634</span>    @Override<a name="line.3634"></a>
-<span class="sourceLineNo">3635</span>    public void checkAndPrepare() throws IOException {<a name="line.3635"></a>
-<span class="sourceLineNo">3636</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3636"></a>
-<span class="sourceLineNo">3637</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3637"></a>
-<span class="sourceLineNo">3638</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3638"></a>
-<span class="sourceLineNo">3639</span>        private WALEdit walEdit;<a name="line.3639"></a>
-<span class="sourceLineNo">3640</span>        @Override<a name="line.3640"></a>
-<span class="sourceLineNo">3641</span>        public boolean visit(int index) throws IOException {<a name="line.3641"></a>
-<span class="sourceLineNo">3642</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3642"></a>
-<span class="sourceLineNo">3643</span>          if (region.coprocessorHost != null) {<a name="line.3643"></a>
-<span class="sourceLineNo">3644</span>            if (walEdit == null) {<a name="line.3644"></a>
-<span class="sourceLineNo">3645</span>              walEdit = new WALEdit();<a name="line.3645"></a>
-<span class="sourceLineNo">3646</span>            }<a name="line.3646"></a>
-<span class="sourceLineNo">3647</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3647"></a>
-<span class="sourceLineNo">3648</span>            if (!walEdit.isEmpty()) {<a name="line.3648"></a>
-<span class="sourceLineNo">3649</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3649"></a>
-<span class="sourceLineNo">3650</span>              walEdit = null;<a name="line.3650"></a>
-<span class="sourceLineNo">3651</span>            }<a name="line.3651"></a>
-<span class="sourceLineNo">3652</span>          }<a name="line.3652"></a>
-<span class="sourceLineNo">3653</span>          if (isOperationPending(index)) {<a name="line.3653"></a>
-<span class="sourceLineNo">3654</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3654"></a>
-<span class="sourceLineNo">3655</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3655"></a>
-<span class="sourceLineNo">3656</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3656"></a>
-<span class="sourceLineNo">3657</span>            checkAndPrepareMutation(index, now);<a name="line.3657"></a>
-<span class="sourceLineNo">3658</span>          }<a name="line.3658"></a>
-<span class="sourceLineNo">3659</span>          return true;<a name="line.3659"></a>
-<span class="sourceLineNo">3660</span>        }<a name="line.3660"></a>
-<span class="sourceLineNo">3661</span>      });<a name="line.3661"></a>
-<span class="sourceLineNo">3662</span><a name="line.3662"></a>
-<span class="sourceLineNo">3663</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3663"></a>
-<span class="sourceLineNo">3664</span>      // normal processing.<a name="line.3664"></a>
-<span class="sourceLineNo">3665</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3665"></a>
-<span class="sourceLineNo">3666</span>      // update general metrics though a Coprocessor did the work).<a name="line.3666"></a>
-<span class="sourceLineNo">3667</span>      if (region.metricsRegion != null) {<a name="line.3667"></a>
-<span class="sourceLineNo">3668</span>        if (metrics[0] &gt; 0) {<a name="line.3668"></a>
-<span class="sourceLineNo">3669</span>          // There were some Puts in the batch.<a name="line.3669"></a>
-<span class="sourceLineNo">3670</span>          region.metricsRegion.updatePut();<a name="line.3670"></a>
-<span class="sourceLineNo">3671</span>        }<a name="line.3671"></a>
-<span class="sourceLineNo">3672</span>        if (metrics[1] &gt; 0) {<a name="line.3672"></a>
-<span class="sourceLineNo">3673</span>          // There were some Deletes in the batch.<a name="line.3673"></a>
-<span class="sourceLineNo">3674</span>          region.metricsRegion.updateDelete();<a name="line.3674"></a>
-<span class="sourceLineNo">3675</span>        }<a name="line.3675"></a>
-<span class="sourceLineNo">3676</span>      }<a name="line.3676"></a>
-<span class="sourceLineNo">3677</span>    }<a name="line.3677"></a>
-<span class="sourceLineNo">3678</span><a name="line.3678"></a>
-<span class="sourceLineNo">3679</span>    @Override<a name="line.3679"></a>
-<span class="sourceLineNo">3680</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3680"></a>
-<span class="sourceLineNo">3681</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3681"></a>
-<span class="sourceLineNo">3682</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3682"></a>
-<span class="sourceLineNo">3683</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3683"></a>
-<span class="sourceLineNo">3684</span>        Mutation mutation = getMutation(index);<a name="line.3684"></a>
-<span class="sourceLineNo">3685</span>        if (mutation instanceof Put) {<a name="line.3685"></a>
-<span class="sourceLineNo">3686</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3686"></a>
-<span class="sourceLineNo">3687</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3687"></a>
-<span class="sourceLineNo">3688</span>        } else {<a name="line.3688"></a>
-<span class="sourceLineNo">3689</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3689"></a>
-<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3690"></a>
-<span class="sourceLineNo">3691</span>        }<a name="line.3691"></a>
-<span class="sourceLineNo">3692</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3692"></a>
-<span class="sourceLineNo">3693</span><a name="line.3693"></a>
-<span class="sourceLineNo">3694</span>        // update cell count<a name="line.3694"></a>
-<span class="sourceLineNo">3695</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3695"></a>
-<span class="sourceLineNo">3696</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3696"></a>
-<span class="sourceLineNo">3697</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3697"></a>
-<span class="sourceLineNo">3698</span>          }<a name="line.3698"></a>
-<span class="sourceLineNo">3699</span>        }<a name="line.3699"></a>
-<span class="sourceLineNo">3700</span><a name="line.3700"></a>
-<span class="sourceLineNo">3701</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3701"></a>
-<span class="sourceLineNo">3702</span>        if (fromCP != null) {<a name="line.3702"></a>
-<span class="sourceLineNo">3703</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3703"></a>
-<span class="sourceLineNo">3704</span>        }<a name="line.3704"></a>
-<span class="sourceLineNo">3705</span>        return true;<a name="line.3705"></a>
-<span class="sourceLineNo">3706</span>      });<a name="line.3706"></a>
-<span class="sourceLineNo">3707</span><a name="line.3707"></a>
-<span class="sourceLineNo">3708</span>      if (region.coprocessorHost != null) {<a name="line.3708"></a>
-<span class="sourceLineNo">3709</span>        // calling the pre CP hook for batch mutation<a name="line.3709"></a>
-<span class="sourceLineNo">3710</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3710"></a>
-<span class="sourceLineNo">3711</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3711"></a>
-<span class="sourceLineNo">3712</span>      }<a name="line.3712"></a>
-<span class="sourceLineNo">3713</span>    }<a name="line.3713"></a>
-<span class="sourceLineNo">3714</span><a name="line.3714"></a>
-<span class="sourceLineNo">3715</span>    @Override<a name="line.3715"></a>
-<span class="sourceLineNo">3716</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3716"></a>
-<span class="sourceLineNo">3717</span>        miniBatchOp) throws IOException {<a name="line.3717"></a>
-<span class="sourceLineNo">3718</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3718"></a>
-<span class="sourceLineNo">3719</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3719"></a>
-<span class="sourceLineNo">3720</span>      if (walEdits.size() &gt; 1) {<a name="line.3720"></a>
-<span class="sourceLineNo">3721</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3721"></a>
-<span class="sourceLineNo">3722</span>      }<a name="line.3722"></a>
-<span class="sourceLineNo">3723</span>      return walEdits;<a name="line.3723"></a>
-<span class="sourceLineNo">3724</span>    }<a name="line.3724"></a>
-<span class="sourceLineNo">3725</span><a name="line.3725"></a>
-<span class="sourceLineNo">3726</span>    @Override<a name="line.3726"></a>
-<span class="sourceLineNo">3727</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3727"></a>
-<span class="sourceLineNo">3728</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3728"></a>
-<span class="sourceLineNo">3729</span>        throws IOException {<a name="line.3729"></a>
-<span class="sourceLineNo">3730</span>      if (writeEntry == null) {<a name="line.3730"></a>
-<span class="sourceLineNo">3731</span>        writeEntry = region.mvcc.begin();<a name="line.3731"></a>
-<span class="sourceLineNo">3732</span>      }<a name="line.3732"></a>
-<span class="sourceLineNo">3733</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3733"></a>
-<span class="sourceLineNo">3734</span>      return writeEntry;<a name="line.3734"></a>
-<span class="sourceLineNo">3735</span>    }<a name="line.3735"></a>
-<span class="sourceLineNo">3736</span><a name="line.3736"></a>
-<span class="sourceLineNo">3737</span>    @Override<a name="line.3737"></a>
-<span class="sourceLineNo">3738</span>    public void completeMiniBatchOperations(<a name="line.3738"></a>
-<span class="sourceLineNo">3739</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3739"></a>
-<span class="sourceLineNo">3740</span>        throws IOException {<a name="line.3740"></a>
-<span class="sourceLineNo">3741</span>      // TODO: can it be done after completing mvcc?<a name="line.3741"></a>
-<span class="sourceLineNo">3742</span>      // calling the post CP hook for batch mutation<a name="line.3742"></a>
-<span class="sourceLineNo">3743</span>      if (region.coprocessorHost != null) {<a name="line.3743"></a>
-<span class="sourceLineNo">3744</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3744"></a>
-<span class="sourceLineNo">3745</span>      }<a name="line.3745"></a>
-<span class="sourceLineNo">3746</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3746"></a>
-<span class="sourceLineNo">3747</span>    }<a name="line.3747"></a>
-<span class="sourceLineNo">3748</span><a name="line.3748"></a>
-<span class="sourceLineNo">3749</span>    @Override<a name="line.3749"></a>
-<span class="sourceLineNo">3750</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3750"></a>
-<span class="sourceLineNo">3751</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3751"></a>
-<span class="sourceLineNo">3752</span><a name="line.3752"></a>
-<span class="sourceLineNo">3753</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3753"></a>
-<span class="sourceLineNo">3754</span>      if (miniBatchOp != null) {<a name="line.3754"></a>
-<span class="sourceLineNo">3755</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3755"></a>
-<span class="sourceLineNo">3756</span>        if (region.coprocessorHost != null) {<a name="line.3756"></a>
-<span class="sourceLineNo">3757</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3757"></a>
-<span class="sourceLineNo">3758</span>            // only for successful puts<a name="line.3758"></a>
-<span class="sourceLineNo">3759</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3759"></a>
-<span class="sourceLineNo">3760</span>              Mutation m = getMutation(i);<a name="line.3760"></a>
-<span class="sourceLineNo">3761</span>              if (m instanceof Put) {<a name="line.3761"></a>
-<span class="sourceLineNo">3762</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3762"></a>
-<span class="sourceLineNo">3763</span>              } else {<a name="line.3763"></a>
-<span class="sourceLineNo">3764</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3764"></a>
-<span class="sourceLineNo">3765</span>              }<a name="line.3765"></a>
-<span class="sourceLineNo">3766</span>            }<a name="line.3766"></a>
-<span class="sourceLineNo">3767</span>            return true;<a name="line.3767"></a>
-<span class="sourceLineNo">3768</span>          });<a name="line.3768"></a>
-<span class="sourceLineNo">3769</span>        }<a name="line.3769"></a>
-<span class="sourceLineNo">3770</span><a name="line.3770"></a>
-<span class="sourceLineNo">3771</span>        // See if the column families were consistent through the whole thing.<a name="line.3771"></a>
-<span class="sourceLineNo">3772</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3772"></a>
-<span class="sourceLineNo">3773</span>        // null will be treated as unknown.<a name="line.3773"></a>
-<span class="sourceLineNo">3774</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3774"></a>
-<span class="sourceLineNo">3775</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3775"></a>
-<span class="sourceLineNo">3776</span>        if (region.metricsRegion != null) {<a name="line.3776"></a>
-<span class="sourceLineNo">3777</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3777"></a>
-<span class="sourceLineNo">3778</span>            // There were some Puts in the batch.<a name="line.3778"></a>
-<span class="sourceLineNo">3779</span>            region.metricsRegion.updatePut();<a name="line.3779"></a>
-<span class="sourceLineNo">3780</span>          }<a name="line.3780"></a>
-<span class="sourceLineNo">3781</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3781"></a>
-<span class="sourceLineNo">3782</span>            // There were some Deletes in the batch.<a name="line.3782"></a>
-<span class="sourceLineNo">3783</span>            region.metricsRegion.updateDelete();<a name="line.3783"></a>
-<span class="sourceLineNo">3784</span>          }<a name="line.3784"></a>
-<span class="sourceLineNo">3785</span>        }<a name="line.3785"></a>
-<span class="sourceLineNo">3786</span>      }<a name="line.3786"></a>
-<span class="sourceLineNo">3787</span><a name="line.3787"></a>
-<span class="sourceLineNo">3788</span>      if (region.coprocessorHost != null) {<a name="line.3788"></a>
-<span class="sourceLineNo">3789</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3789"></a>
-<span class="sourceLineNo">3790</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3790"></a>
-<span class="sourceLineNo">3791</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3791"></a>
-<span class="sourceLineNo">3792</span>      }<a name="line.3792"></a>
-<span class="sourceLineNo">3793</span>    }<a name="line.3793"></a>
-<span class="sourceLineNo">3794</span><a name="line.3794"></a>
-<span class="sourceLineNo">3795</span>    /**<a name="line.3795"></a>
-<span class="sourceLineNo">3796</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3796"></a>
-<span class="sourceLineNo">3797</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3797"></a>
-<span class="sourceLineNo">3798</span>     */<a name="line.3798"></a>
-<span class="sourceLineNo">3799</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3799"></a>
-<span class="sourceLineNo">3800</span>        throws IOException {<a name="line.3800"></a>
-<span class="sourceLineNo">3801</span>      Mutation m = getMutation(index);<a name="line.3801"></a>
-<span class="sourceLineNo">3802</span>      if (m instanceof Put) {<a name="line.3802"></a>
-<span class="sourceLineNo">3803</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3803"></a>
-<span class="sourceLineNo">3804</span>          // pre hook says skip this Put<a name="line.3804"></a>
-<span class="sourceLineNo">3805</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3805"></a>
-<span class="sourceLineNo">3806</span>          metrics[0]++;<a name="line.3806"></a>
-<span class="sourceLineNo">3807</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3807"></a>
-<span class="sourceLineNo">3808</span>        }<a name="line.3808"></a>
-<span class="sourceLineNo">3809</span>      } else if (m instanceof Delete) {<a name="line.3809"></a>
-<span class="sourceLineNo">3810</span>        Delete curDel = (Delete) m;<a name="line.3810"></a>
-<span class="sourceLineNo">3811</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3811"></a>
-<span class="sourceLineNo">3812</span>          // handle deleting a row case<a name="line.3812"></a>
-<span class="sourceLineNo">3813</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3813"></a>
-<span class="sourceLineNo">3814</span>          // Can this be avoided?<a name="line.3814"></a>
-<span class="sourceLineNo">3815</span>          region.prepareDelete(curDel);<a name="line.3815"></a>
-<span class="sourceLineNo">3816</span>        }<a name="line.3816"></a>
-<span class="sourceLineNo">3817</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3817"></a>
-<span class="sourceLineNo">3818</span>          // pre hook says skip this Delete<a name="line.3818"></a>
-<span class="sourceLineNo">3819</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3819"></a>
-<span class="sourceLineNo">3820</span>          metrics[1]++;<a name="line.3820"></a>
-<span class="sourceLineNo">3821</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3821"></a>
-<span class="sourceLineNo">3822</span>        }<a name="line.3822"></a>
-<span class="sourceLineNo">3823</span>      } else {<a name="line.3823"></a>
-<span class="sourceLineNo">3824</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3824"></a>
-<span class="sourceLineNo">3825</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3825"></a>
-<span class="sourceLineNo">3826</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3826"></a>
-<span class="sourceLineNo">3827</span>        // the doMiniBatchMutation<a name="line.3827"></a>
-<span class="sourceLineNo">3828</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3828"></a>
-<span class="sourceLineNo">3829</span><a name="line.3829"></a>
-<span class="sourceLineNo">3830</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3830"></a>
-<span class="sourceLineNo">3831</span>          throw new IOException(msg);<a name="line.3831"></a>
-<span class="sourceLineNo">3832</span>        }<a name="line.3832"></a>
-<span class="sourceLineNo">3833</span>      }<a name="line.3833"></a>
-<span class="sourceLineNo">3834</span>    }<a name="line.3834"></a>
-<span class="sourceLineNo">3835</span><a name="line.3835"></a>
-<span class="sourceLineNo">3836</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3836"></a>
-<span class="sourceLineNo">3837</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3837"></a>
-<span class="sourceLineNo">3838</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3838"></a>
-<span class="sourceLineNo">3839</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3839"></a>
-<span class="sourceLineNo">3840</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3840"></a>
-<span class="sourceLineNo">3841</span>        if (cpMutations == null) {<a name="line.3841"></a>
-<span class="sourceLineNo">3842</span>          return true;<a name="line.3842"></a>
-<span class="sourceLineNo">3843</span>        }<a name="line.3843"></a>
-<span class="sourceLineNo">3844</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3844"></a>
-<span class="sourceLineNo">3845</span>        Mutation mutation = getMutation(i);<a name="line.3845"></a>
-<span class="sourceLineNo">3846</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3846"></a>
-<span class="sourceLineNo">3847</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3847"></a>
-<span class="sourceLineNo">3848</span><a name="line.3848"></a>
-<span class="sourceLineNo">3849</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3849"></a>
-<span class="sourceLineNo">3850</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3850"></a>
+<span class="sourceLineNo">3469</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {<a name="line.3469"></a>
+<span class="sourceLineNo">3470</span>        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;<a name="line.3470"></a>
+<span class="sourceLineNo">3471</span><a name="line.3471"></a>
+<span class="sourceLineNo">3472</span>        @Override<a name="line.3472"></a>
+<span class="sourceLineNo">3473</span>        public boolean visit(int index) throws IOException {<a name="line.3473"></a>
+<span class="sourceLineNo">3474</span>          Mutation m = getMutation(index);<a name="line.3474"></a>
+<span class="sourceLineNo">3475</span>          // we use durability of the original mutation for the mutation passed by CP.<a name="line.3475"></a>
+<span class="sourceLineNo">3476</span>          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {<a name="line.3476"></a>
+<span class="sourceLineNo">3477</span>            region.recordMutationWithoutWal(m.getFamilyCellMap());<a name="line.3477"></a>
+<span class="sourceLineNo">3478</span>            return true;<a name="line.3478"></a>
+<span class="sourceLineNo">3479</span>          }<a name="line.3479"></a>
+<span class="sourceLineNo">3480</span><a name="line.3480"></a>
+<span class="sourceLineNo">3481</span>          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.<a name="line.3481"></a>
+<span class="sourceLineNo">3482</span>          // Given how nonce keys are originally written, these should be contiguous.<a name="line.3482"></a>
+<span class="sourceLineNo">3483</span>          // They don't have to be, it will still work, just write more WALEdits than needed.<a name="line.3483"></a>
+<span class="sourceLineNo">3484</span>          long nonceGroup = getNonceGroup(index);<a name="line.3484"></a>
+<span class="sourceLineNo">3485</span>          long nonce = getNonce(index);<a name="line.3485"></a>
+<span class="sourceLineNo">3486</span>          if (curWALEditForNonce == null ||<a name="line.3486"></a>
+<span class="sourceLineNo">3487</span>              curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup ||<a name="line.3487"></a>
+<span class="sourceLineNo">3488</span>              curWALEditForNonce.getFirst().getNonce() != nonce) {<a name="line.3488"></a>
+<span class="sourceLineNo">3489</span>            curWALEditForNonce = new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce),<a name="line.3489"></a>
+<span class="sourceLineNo">3490</span>                new WALEdit(miniBatchOp.getCellCount(), isInReplay()));<a name="line.3490"></a>
+<span class="sourceLineNo">3491</span>            walEdits.add(curWALEditForNonce);<a name="line.3491"></a>
+<span class="sourceLineNo">3492</span>          }<a name="line.3492"></a>
+<span class="sourceLineNo">3493</span>          WALEdit walEdit = curWALEditForNonce.getSecond();<a name="line.3493"></a>
+<span class="sourceLineNo">3494</span><a name="line.3494"></a>
+<span class="sourceLineNo">3495</span>          // Add WAL edits from CPs.<a name="line.3495"></a>
+<span class="sourceLineNo">3496</span>          WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3496"></a>
+<span class="sourceLineNo">3497</span>          if (fromCP != null) {<a name="line.3497"></a>
+<span class="sourceLineNo">3498</span>            for (Cell cell : fromCP.getCells()) {<a name="line.3498"></a>
+<span class="sourceLineNo">3499</span>              walEdit.add(cell);<a name="line.3499"></a>
+<span class="sourceLineNo">3500</span>            }<a name="line.3500"></a>
+<span class="sourceLineNo">3501</span>          }<a name="line.3501"></a>
+<span class="sourceLineNo">3502</span>          walEdit.add(familyCellMaps[index]);<a name="line.3502"></a>
+<span class="sourceLineNo">3503</span><a name="line.3503"></a>
+<span class="sourceLineNo">3504</span>          return true;<a name="line.3504"></a>
+<span class="sourceLineNo">3505</span>        }<a name="line.3505"></a>
+<span class="sourceLineNo">3506</span>      });<a name="line.3506"></a>
+<span class="sourceLineNo">3507</span>      return walEdits;<a name="line.3507"></a>
+<span class="sourceLineNo">3508</span>    }<a name="line.3508"></a>
+<span class="sourceLineNo">3509</span><a name="line.3509"></a>
+<span class="sourceLineNo">3510</span>    /**<a name="line.3510"></a>
+<span class="sourceLineNo">3511</span>     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if<a name="line.3511"></a>
+<span class="sourceLineNo">3512</span>     * required) and completing mvcc.<a name="line.3512"></a>
+<span class="sourceLineNo">3513</span>     */<a name="line.3513"></a>
+<span class="sourceLineNo">3514</span>    public void completeMiniBatchOperations(<a name="line.3514"></a>
+<span class="sourceLineNo">3515</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3515"></a>
+<span class="sourceLineNo">3516</span>        throws IOException {<a name="line.3516"></a>
+<span class="sourceLineNo">3517</span>      if (writeEntry != null) {<a name="line.3517"></a>
+<span class="sourceLineNo">3518</span>        region.mvcc.completeAndWait(writeEntry);<a name="line.3518"></a>
+<span class="sourceLineNo">3519</span>      }<a name="line.3519"></a>
+<span class="sourceLineNo">3520</span>    }<a name="line.3520"></a>
+<span class="sourceLineNo">3521</span><a name="line.3521"></a>
+<span class="sourceLineNo">3522</span>    public void doPostOpCleanupForMiniBatch(<a name="line.3522"></a>
+<span class="sourceLineNo">3523</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,<a name="line.3523"></a>
+<span class="sourceLineNo">3524</span>        boolean success) throws IOException {<a name="line.3524"></a>
+<span class="sourceLineNo">3525</span>      doFinishHotnessProtector(miniBatchOp);<a name="line.3525"></a>
+<span class="sourceLineNo">3526</span>    }<a name="line.3526"></a>
+<span class="sourceLineNo">3527</span><a name="line.3527"></a>
+<span class="sourceLineNo">3528</span>    private void doFinishHotnessProtector(<a name="line.3528"></a>
+<span class="sourceLineNo">3529</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {<a name="line.3529"></a>
+<span class="sourceLineNo">3530</span>      // check and return if the protector is not enabled<a name="line.3530"></a>
+<span class="sourceLineNo">3531</span>      if (!region.storeHotnessProtector.isEnable()) {<a name="line.3531"></a>
+<span class="sourceLineNo">3532</span>        return;<a name="line.3532"></a>
+<span class="sourceLineNo">3533</span>      }<a name="line.3533"></a>
+<span class="sourceLineNo">3534</span>      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.<a name="line.3534"></a>
+<span class="sourceLineNo">3535</span>      // This case was handled.<a name="line.3535"></a>
+<span class="sourceLineNo">3536</span>      if (miniBatchOp == null) {<a name="line.3536"></a>
+<span class="sourceLineNo">3537</span>        return;<a name="line.3537"></a>
+<span class="sourceLineNo">3538</span>      }<a name="line.3538"></a>
+<span class="sourceLineNo">3539</span><a name="line.3539"></a>
+<span class="sourceLineNo">3540</span>      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();<a name="line.3540"></a>
+<span class="sourceLineNo">3541</span><a name="line.3541"></a>
+<span class="sourceLineNo">3542</span>      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {<a name="line.3542"></a>
+<span class="sourceLineNo">3543</span>        switch (retCodeDetails[i].getOperationStatusCode()) {<a name="line.3543"></a>
+<span class="sourceLineNo">3544</span>          case SUCCESS:<a name="line.3544"></a>
+<span class="sourceLineNo">3545</span>          case FAILURE:<a name="line.3545"></a>
+<span class="sourceLineNo">3546</span>            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());<a name="line.3546"></a>
+<span class="sourceLineNo">3547</span>            break;<a name="line.3547"></a>
+<span class="sourceLineNo">3548</span>          default:<a name="line.3548"></a>
+<span class="sourceLineNo">3549</span>            // do nothing<a name="line.3549"></a>
+<span class="sourceLineNo">3550</span>            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the<a name="line.3550"></a>
+<span class="sourceLineNo">3551</span>            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start<a name="line.3551"></a>
+<span class="sourceLineNo">3552</span>            break;<a name="line.3552"></a>
+<span class="sourceLineNo">3553</span>        }<a name="line.3553"></a>
+<span class="sourceLineNo">3554</span>      }<a name="line.3554"></a>
+<span class="sourceLineNo">3555</span>    }<a name="line.3555"></a>
+<span class="sourceLineNo">3556</span><a name="line.3556"></a>
+<span class="sourceLineNo">3557</span>    /**<a name="line.3557"></a>
+<span class="sourceLineNo">3558</span>     * Atomically apply the given map of family-&gt;edits to the memstore.<a name="line.3558"></a>
+<span class="sourceLineNo">3559</span>     * This handles the consistency control on its own, but the caller<a name="line.3559"></a>
+<span class="sourceLineNo">3560</span>     * should already have locked updatesLock.readLock(). This also does<a name="line.3560"></a>
+<span class="sourceLineNo">3561</span>     * &lt;b&gt;not&lt;/b&gt; check the families for validity.<a name="line.3561"></a>
+<span class="sourceLineNo">3562</span>     *<a name="line.3562"></a>
+<span class="sourceLineNo">3563</span>     * @param familyMap Map of Cells by family<a name="line.3563"></a>
+<span class="sourceLineNo">3564</span>     */<a name="line.3564"></a>
+<span class="sourceLineNo">3565</span>    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3565"></a>
+<span class="sourceLineNo">3566</span>        MemStoreSizing memstoreAccounting) throws IOException {<a name="line.3566"></a>
+<span class="sourceLineNo">3567</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e : familyMap.entrySet()) {<a name="line.3567"></a>
+<span class="sourceLineNo">3568</span>        byte[] family = e.getKey();<a name="line.3568"></a>
+<span class="sourceLineNo">3569</span>        List&lt;Cell&gt; cells = e.getValue();<a name="line.3569"></a>
+<span class="sourceLineNo">3570</span>        assert cells instanceof RandomAccess;<a name="line.3570"></a>
+<span class="sourceLineNo">3571</span>        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);<a name="line.3571"></a>
+<span class="sourceLineNo">3572</span>      }<a name="line.3572"></a>
+<span class="sourceLineNo">3573</span>    }<a name="line.3573"></a>
+<span class="sourceLineNo">3574</span>  }<a name="line.3574"></a>
+<span class="sourceLineNo">3575</span><a name="line.3575"></a>
+<span class="sourceLineNo">3576</span><a name="line.3576"></a>
+<span class="sourceLineNo">3577</span>  /**<a name="line.3577"></a>
+<span class="sourceLineNo">3578</span>   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most<a name="line.3578"></a>
+<span class="sourceLineNo">3579</span>   * of the logic is same.<a name="line.3579"></a>
+<span class="sourceLineNo">3580</span>   */<a name="line.3580"></a>
+<span class="sourceLineNo">3581</span>  static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {<a name="line.3581"></a>
+<span class="sourceLineNo">3582</span>    private long nonceGroup;<a name="line.3582"></a>
+<span class="sourceLineNo">3583</span>    private long nonce;<a name="line.3583"></a>
+<span class="sourceLineNo">3584</span>    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,<a name="line.3584"></a>
+<span class="sourceLineNo">3585</span>        long nonceGroup, long nonce) {<a name="line.3585"></a>
+<span class="sourceLineNo">3586</span>      super(region, operations);<a name="line.3586"></a>
+<span class="sourceLineNo">3587</span>      this.atomic = atomic;<a name="line.3587"></a>
+<span class="sourceLineNo">3588</span>      this.nonceGroup = nonceGroup;<a name="line.3588"></a>
+<span class="sourceLineNo">3589</span>      this.nonce = nonce;<a name="line.3589"></a>
+<span class="sourceLineNo">3590</span>    }<a name="line.3590"></a>
+<span class="sourceLineNo">3591</span><a name="line.3591"></a>
+<span class="sourceLineNo">3592</span>    @Override<a name="line.3592"></a>
+<span class="sourceLineNo">3593</span>    public Mutation getMutation(int index) {<a name="line.3593"></a>
+<span class="sourceLineNo">3594</span>      return this.operations[index];<a name="line.3594"></a>
+<span class="sourceLineNo">3595</span>    }<a name="line.3595"></a>
+<span class="sourceLineNo">3596</span><a name="line.3596"></a>
+<span class="sourceLineNo">3597</span>    @Override<a name="line.3597"></a>
+<span class="sourceLineNo">3598</span>    public long getNonceGroup(int index) {<a name="line.3598"></a>
+<span class="sourceLineNo">3599</span>      return nonceGroup;<a name="line.3599"></a>
+<span class="sourceLineNo">3600</span>    }<a name="line.3600"></a>
+<span class="sourceLineNo">3601</span><a name="line.3601"></a>
+<span class="sourceLineNo">3602</span>    @Override<a name="line.3602"></a>
+<span class="sourceLineNo">3603</span>    public long getNonce(int index) {<a name="line.3603"></a>
+<span class="sourceLineNo">3604</span>      return nonce;<a name="line.3604"></a>
+<span class="sourceLineNo">3605</span>    }<a name="line.3605"></a>
+<span class="sourceLineNo">3606</span><a name="line.3606"></a>
+<span class="sourceLineNo">3607</span>    @Override<a name="line.3607"></a>
+<span class="sourceLineNo">3608</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3608"></a>
+<span class="sourceLineNo">3609</span>      return this.operations;<a name="line.3609"></a>
+<span class="sourceLineNo">3610</span>    }<a name="line.3610"></a>
+<span class="sourceLineNo">3611</span><a name="line.3611"></a>
+<span class="sourceLineNo">3612</span>    @Override<a name="line.3612"></a>
+<span class="sourceLineNo">3613</span>    public boolean isInReplay() {<a name="line.3613"></a>
+<span class="sourceLineNo">3614</span>      return false;<a name="line.3614"></a>
+<span class="sourceLineNo">3615</span>    }<a name="line.3615"></a>
+<span class="sourceLineNo">3616</span><a name="line.3616"></a>
+<span class="sourceLineNo">3617</span>    @Override<a name="line.3617"></a>
+<span class="sourceLineNo">3618</span>    public long getOrigLogSeqNum() {<a name="line.3618"></a>
+<span class="sourceLineNo">3619</span>      return SequenceId.NO_SEQUENCE_ID;<a name="line.3619"></a>
+<span class="sourceLineNo">3620</span>    }<a name="line.3620"></a>
+<span class="sourceLineNo">3621</span><a name="line.3621"></a>
+<span class="sourceLineNo">3622</span>    @Override<a name="line.3622"></a>
+<span class="sourceLineNo">3623</span>    public void startRegionOperation() throws IOException {<a name="line.3623"></a>
+<span class="sourceLineNo">3624</span>      region.startRegionOperation(Operation.BATCH_MUTATE);<a name="line.3624"></a>
+<span class="sourceLineNo">3625</span>    }<a name="line.3625"></a>
+<span class="sourceLineNo">3626</span><a name="line.3626"></a>
+<span class="sourceLineNo">3627</span>    @Override<a name="line.3627"></a>
+<span class="sourceLineNo">3628</span>    public void closeRegionOperation() throws IOException {<a name="line.3628"></a>
+<span class="sourceLineNo">3629</span>      region.closeRegionOperation(Operation.BATCH_MUTATE);<a name="line.3629"></a>
+<span class="sourceLineNo">3630</span>    }<a name="line.3630"></a>
+<span class="sourceLineNo">3631</span><a name="line.3631"></a>
+<span class="sourceLineNo">3632</span>    @Override<a name="line.3632"></a>
+<span class="sourceLineNo">3633</span>    public void checkAndPreparePut(Put p) throws IOException {<a name="line.3633"></a>
+<span class="sourceLineNo">3634</span>      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());<a name="line.3634"></a>
+<span class="sourceLineNo">3635</span>    }<a name="line.3635"></a>
+<span class="sourceLineNo">3636</span><a name="line.3636"></a>
+<span class="sourceLineNo">3637</span>    @Override<a name="line.3637"></a>
+<span class="sourceLineNo">3638</span>    public void checkAndPrepare() throws IOException {<a name="line.3638"></a>
+<span class="sourceLineNo">3639</span>      final int[] metrics = {0, 0}; // index 0: puts, index 1: deletes<a name="line.3639"></a>
+<span class="sourceLineNo">3640</span>      visitBatchOperations(true, this.size(), new Visitor() {<a name="line.3640"></a>
+<span class="sourceLineNo">3641</span>        private long now = EnvironmentEdgeManager.currentTime();<a name="line.3641"></a>
+<span class="sourceLineNo">3642</span>        private WALEdit walEdit;<a name="line.3642"></a>
+<span class="sourceLineNo">3643</span>        @Override<a name="line.3643"></a>
+<span class="sourceLineNo">3644</span>        public boolean visit(int index) throws IOException {<a name="line.3644"></a>
+<span class="sourceLineNo">3645</span>          // Run coprocessor pre hook outside of locks to avoid deadlock<a name="line.3645"></a>
+<span class="sourceLineNo">3646</span>          if (region.coprocessorHost != null) {<a name="line.3646"></a>
+<span class="sourceLineNo">3647</span>            if (walEdit == null) {<a name="line.3647"></a>
+<span class="sourceLineNo">3648</span>              walEdit = new WALEdit();<a name="line.3648"></a>
+<span class="sourceLineNo">3649</span>            }<a name="line.3649"></a>
+<span class="sourceLineNo">3650</span>            callPreMutateCPHook(index, walEdit, metrics);<a name="line.3650"></a>
+<span class="sourceLineNo">3651</span>            if (!walEdit.isEmpty()) {<a name="line.3651"></a>
+<span class="sourceLineNo">3652</span>              walEditsFromCoprocessors[index] = walEdit;<a name="line.3652"></a>
+<span class="sourceLineNo">3653</span>              walEdit = null;<a name="line.3653"></a>
+<span class="sourceLineNo">3654</span>            }<a name="line.3654"></a>
+<span class="sourceLineNo">3655</span>          }<a name="line.3655"></a>
+<span class="sourceLineNo">3656</span>          if (isOperationPending(index)) {<a name="line.3656"></a>
+<span class="sourceLineNo">3657</span>            // TODO: Currently validation is done with current time before acquiring locks and<a name="line.3657"></a>
+<span class="sourceLineNo">3658</span>            // updates are done with different timestamps after acquiring locks. This behavior is<a name="line.3658"></a>
+<span class="sourceLineNo">3659</span>            // inherited from the code prior to this change. Can this be changed?<a name="line.3659"></a>
+<span class="sourceLineNo">3660</span>            checkAndPrepareMutation(index, now);<a name="line.3660"></a>
+<span class="sourceLineNo">3661</span>          }<a name="line.3661"></a>
+<span class="sourceLineNo">3662</span>          return true;<a name="line.3662"></a>
+<span class="sourceLineNo">3663</span>        }<a name="line.3663"></a>
+<span class="sourceLineNo">3664</span>      });<a name="line.3664"></a>
+<span class="sourceLineNo">3665</span><a name="line.3665"></a>
+<span class="sourceLineNo">3666</span>      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in<a name="line.3666"></a>
+<span class="sourceLineNo">3667</span>      // normal processing.<a name="line.3667"></a>
+<span class="sourceLineNo">3668</span>      // Update metrics in same way as it is done when we go the normal processing route (we now<a name="line.3668"></a>
+<span class="sourceLineNo">3669</span>      // update general metrics though a Coprocessor did the work).<a name="line.3669"></a>
+<span class="sourceLineNo">3670</span>      if (region.metricsRegion != null) {<a name="line.3670"></a>
+<span class="sourceLineNo">3671</span>        if (metrics[0] &gt; 0) {<a name="line.3671"></a>
+<span class="sourceLineNo">3672</span>          // There were some Puts in the batch.<a name="line.3672"></a>
+<span class="sourceLineNo">3673</span>          region.metricsRegion.updatePut();<a name="line.3673"></a>
+<span class="sourceLineNo">3674</span>        }<a name="line.3674"></a>
+<span class="sourceLineNo">3675</span>        if (metrics[1] &gt; 0) {<a name="line.3675"></a>
+<span class="sourceLineNo">3676</span>          // There were some Deletes in the batch.<a name="line.3676"></a>
+<span class="sourceLineNo">3677</span>          region.metricsRegion.updateDelete();<a name="line.3677"></a>
+<span class="sourceLineNo">3678</span>        }<a name="line.3678"></a>
+<span class="sourceLineNo">3679</span>      }<a name="line.3679"></a>
+<span class="sourceLineNo">3680</span>    }<a name="line.3680"></a>
+<span class="sourceLineNo">3681</span><a name="line.3681"></a>
+<span class="sourceLineNo">3682</span>    @Override<a name="line.3682"></a>
+<span class="sourceLineNo">3683</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3683"></a>
+<span class="sourceLineNo">3684</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3684"></a>
+<span class="sourceLineNo">3685</span>      byte[] byteTS = Bytes.toBytes(timestamp);<a name="line.3685"></a>
+<span class="sourceLineNo">3686</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3686"></a>
+<span class="sourceLineNo">3687</span>        Mutation mutation = getMutation(index);<a name="line.3687"></a>
+<span class="sourceLineNo">3688</span>        if (mutation instanceof Put) {<a name="line.3688"></a>
+<span class="sourceLineNo">3689</span>          HRegion.updateCellTimestamps(familyCellMaps[index].values(), byteTS);<a name="line.3689"></a>
+<span class="sourceLineNo">3690</span>          miniBatchOp.incrementNumOfPuts();<a name="line.3690"></a>
+<span class="sourceLineNo">3691</span>        } else {<a name="line.3691"></a>
+<span class="sourceLineNo">3692</span>          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], byteTS);<a name="line.3692"></a>
+<span class="sourceLineNo">3693</span>          miniBatchOp.incrementNumOfDeletes();<a name="line.3693"></a>
+<span class="sourceLineNo">3694</span>        }<a name="line.3694"></a>
+<span class="sourceLineNo">3695</span>        region.rewriteCellTags(familyCellMaps[index], mutation);<a name="line.3695"></a>
+<span class="sourceLineNo">3696</span><a name="line.3696"></a>
+<span class="sourceLineNo">3697</span>        // update cell count<a name="line.3697"></a>
+<span class="sourceLineNo">3698</span>        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3698"></a>
+<span class="sourceLineNo">3699</span>          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {<a name="line.3699"></a>
+<span class="sourceLineNo">3700</span>            miniBatchOp.addCellCount(cells.size());<a name="line.3700"></a>
+<span class="sourceLineNo">3701</span>          }<a name="line.3701"></a>
+<span class="sourceLineNo">3702</span>        }<a name="line.3702"></a>
+<span class="sourceLineNo">3703</span><a name="line.3703"></a>
+<span class="sourceLineNo">3704</span>        WALEdit fromCP = walEditsFromCoprocessors[index];<a name="line.3704"></a>
+<span class="sourceLineNo">3705</span>        if (fromCP != null) {<a name="line.3705"></a>
+<span class="sourceLineNo">3706</span>          miniBatchOp.addCellCount(fromCP.size());<a name="line.3706"></a>
+<span class="sourceLineNo">3707</span>        }<a name="line.3707"></a>
+<span class="sourceLineNo">3708</span>        return true;<a name="line.3708"></a>
+<span class="sourceLineNo">3709</span>      });<a name="line.3709"></a>
+<span class="sourceLineNo">3710</span><a name="line.3710"></a>
+<span class="sourceLineNo">3711</span>      if (region.coprocessorHost != null) {<a name="line.3711"></a>
+<span class="sourceLineNo">3712</span>        // calling the pre CP hook for batch mutation<a name="line.3712"></a>
+<span class="sourceLineNo">3713</span>        region.coprocessorHost.preBatchMutate(miniBatchOp);<a name="line.3713"></a>
+<span class="sourceLineNo">3714</span>        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);<a name="line.3714"></a>
+<span class="sourceLineNo">3715</span>      }<a name="line.3715"></a>
+<span class="sourceLineNo">3716</span>    }<a name="line.3716"></a>
+<span class="sourceLineNo">3717</span><a name="line.3717"></a>
+<span class="sourceLineNo">3718</span>    @Override<a name="line.3718"></a>
+<span class="sourceLineNo">3719</span>    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt;<a name="line.3719"></a>
+<span class="sourceLineNo">3720</span>        miniBatchOp) throws IOException {<a name="line.3720"></a>
+<span class="sourceLineNo">3721</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);<a name="line.3721"></a>
+<span class="sourceLineNo">3722</span>      // for MutationBatchOperation, more than one nonce is not allowed<a name="line.3722"></a>
+<span class="sourceLineNo">3723</span>      if (walEdits.size() &gt; 1) {<a name="line.3723"></a>
+<span class="sourceLineNo">3724</span>        throw new IOException("Found multiple nonce keys per batch!");<a name="line.3724"></a>
+<span class="sourceLineNo">3725</span>      }<a name="line.3725"></a>
+<span class="sourceLineNo">3726</span>      return walEdits;<a name="line.3726"></a>
+<span class="sourceLineNo">3727</span>    }<a name="line.3727"></a>
+<span class="sourceLineNo">3728</span><a name="line.3728"></a>
+<span class="sourceLineNo">3729</span>    @Override<a name="line.3729"></a>
+<span class="sourceLineNo">3730</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3730"></a>
+<span class="sourceLineNo">3731</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry)<a name="line.3731"></a>
+<span class="sourceLineNo">3732</span>        throws IOException {<a name="line.3732"></a>
+<span class="sourceLineNo">3733</span>      if (writeEntry == null) {<a name="line.3733"></a>
+<span class="sourceLineNo">3734</span>        writeEntry = region.mvcc.begin();<a name="line.3734"></a>
+<span class="sourceLineNo">3735</span>      }<a name="line.3735"></a>
+<span class="sourceLineNo">3736</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());<a name="line.3736"></a>
+<span class="sourceLineNo">3737</span>      return writeEntry;<a name="line.3737"></a>
+<span class="sourceLineNo">3738</span>    }<a name="line.3738"></a>
+<span class="sourceLineNo">3739</span><a name="line.3739"></a>
+<span class="sourceLineNo">3740</span>    @Override<a name="line.3740"></a>
+<span class="sourceLineNo">3741</span>    public void completeMiniBatchOperations(<a name="line.3741"></a>
+<span class="sourceLineNo">3742</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3742"></a>
+<span class="sourceLineNo">3743</span>        throws IOException {<a name="line.3743"></a>
+<span class="sourceLineNo">3744</span>      // TODO: can it be done after completing mvcc?<a name="line.3744"></a>
+<span class="sourceLineNo">3745</span>      // calling the post CP hook for batch mutation<a name="line.3745"></a>
+<span class="sourceLineNo">3746</span>      if (region.coprocessorHost != null) {<a name="line.3746"></a>
+<span class="sourceLineNo">3747</span>        region.coprocessorHost.postBatchMutate(miniBatchOp);<a name="line.3747"></a>
+<span class="sourceLineNo">3748</span>      }<a name="line.3748"></a>
+<span class="sourceLineNo">3749</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3749"></a>
+<span class="sourceLineNo">3750</span>    }<a name="line.3750"></a>
+<span class="sourceLineNo">3751</span><a name="line.3751"></a>
+<span class="sourceLineNo">3752</span>    @Override<a name="line.3752"></a>
+<span class="sourceLineNo">3753</span>    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3753"></a>
+<span class="sourceLineNo">3754</span>        final WALEdit walEdit, boolean success) throws IOException {<a name="line.3754"></a>
+<span class="sourceLineNo">3755</span><a name="line.3755"></a>
+<span class="sourceLineNo">3756</span>      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);<a name="line.3756"></a>
+<span class="sourceLineNo">3757</span>      if (miniBatchOp != null) {<a name="line.3757"></a>
+<span class="sourceLineNo">3758</span>        // synced so that the coprocessor contract is adhered to.<a name="line.3758"></a>
+<span class="sourceLineNo">3759</span>        if (region.coprocessorHost != null) {<a name="line.3759"></a>
+<span class="sourceLineNo">3760</span>          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {<a name="line.3760"></a>
+<span class="sourceLineNo">3761</span>            // only for successful puts<a name="line.3761"></a>
+<span class="sourceLineNo">3762</span>            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {<a name="line.3762"></a>
+<span class="sourceLineNo">3763</span>              Mutation m = getMutation(i);<a name="line.3763"></a>
+<span class="sourceLineNo">3764</span>              if (m instanceof Put) {<a name="line.3764"></a>
+<span class="sourceLineNo">3765</span>                region.coprocessorHost.postPut((Put) m, walEdit, m.getDurability());<a name="line.3765"></a>
+<span class="sourceLineNo">3766</span>              } else {<a name="line.3766"></a>
+<span class="sourceLineNo">3767</span>                region.coprocessorHost.postDelete((Delete) m, walEdit, m.getDurability());<a name="line.3767"></a>
+<span class="sourceLineNo">3768</span>              }<a name="line.3768"></a>
+<span class="sourceLineNo">3769</span>            }<a name="line.3769"></a>
+<span class="sourceLineNo">3770</span>            return true;<a name="line.3770"></a>
+<span class="sourceLineNo">3771</span>          });<a name="line.3771"></a>
+<span class="sourceLineNo">3772</span>        }<a name="line.3772"></a>
+<span class="sourceLineNo">3773</span><a name="line.3773"></a>
+<span class="sourceLineNo">3774</span>        // See if the column families were consistent through the whole thing.<a name="line.3774"></a>
+<span class="sourceLineNo">3775</span>        // if they were then keep them. If they were not then pass a null.<a name="line.3775"></a>
+<span class="sourceLineNo">3776</span>        // null will be treated as unknown.<a name="line.3776"></a>
+<span class="sourceLineNo">3777</span>        // Total time taken might be involving Puts and Deletes.<a name="line.3777"></a>
+<span class="sourceLineNo">3778</span>        // Split the time for puts and deletes based on the total number of Puts and Deletes.<a name="line.3778"></a>
+<span class="sourceLineNo">3779</span>        if (region.metricsRegion != null) {<a name="line.3779"></a>
+<span class="sourceLineNo">3780</span>          if (miniBatchOp.getNumOfPuts() &gt; 0) {<a name="line.3780"></a>
+<span class="sourceLineNo">3781</span>            // There were some Puts in the batch.<a name="line.3781"></a>
+<span class="sourceLineNo">3782</span>            region.metricsRegion.updatePut();<a name="line.3782"></a>
+<span class="sourceLineNo">3783</span>          }<a name="line.3783"></a>
+<span class="sourceLineNo">3784</span>          if (miniBatchOp.getNumOfDeletes() &gt; 0) {<a name="line.3784"></a>
+<span class="sourceLineNo">3785</span>            // There were some Deletes in the batch.<a name="line.3785"></a>
+<span class="sourceLineNo">3786</span>            region.metricsRegion.updateDelete();<a name="line.3786"></a>
+<span class="sourceLineNo">3787</span>          }<a name="line.3787"></a>
+<span class="sourceLineNo">3788</span>        }<a name="line.3788"></a>
+<span class="sourceLineNo">3789</span>      }<a name="line.3789"></a>
+<span class="sourceLineNo">3790</span><a name="line.3790"></a>
+<span class="sourceLineNo">3791</span>      if (region.coprocessorHost != null) {<a name="line.3791"></a>
+<span class="sourceLineNo">3792</span>        // call the coprocessor hook to do any finalization steps after the put is done<a name="line.3792"></a>
+<span class="sourceLineNo">3793</span>        region.coprocessorHost.postBatchMutateIndispensably(<a name="line.3793"></a>
+<span class="sourceLineNo">3794</span>            miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);<a name="line.3794"></a>
+<span class="sourceLineNo">3795</span>      }<a name="line.3795"></a>
+<span class="sourceLineNo">3796</span>    }<a name="line.3796"></a>
+<span class="sourceLineNo">3797</span><a name="line.3797"></a>
+<span class="sourceLineNo">3798</span>    /**<a name="line.3798"></a>
+<span class="sourceLineNo">3799</span>     * Runs prePut/ preDelete coprocessor hook for input mutation in a batch<a name="line.3799"></a>
+<span class="sourceLineNo">3800</span>     * @param metrics Array of 2 ints. index 0: count of puts and index 1: count of deletes<a name="line.3800"></a>
+<span class="sourceLineNo">3801</span>     */<a name="line.3801"></a>
+<span class="sourceLineNo">3802</span>    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)<a name="line.3802"></a>
+<span class="sourceLineNo">3803</span>        throws IOException {<a name="line.3803"></a>
+<span class="sourceLineNo">3804</span>      Mutation m = getMutation(index);<a name="line.3804"></a>
+<span class="sourceLineNo">3805</span>      if (m instanceof Put) {<a name="line.3805"></a>
+<span class="sourceLineNo">3806</span>        if (region.coprocessorHost.prePut((Put) m, walEdit, m.getDurability())) {<a name="line.3806"></a>
+<span class="sourceLineNo">3807</span>          // pre hook says skip this Put<a name="line.3807"></a>
+<span class="sourceLineNo">3808</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3808"></a>
+<span class="sourceLineNo">3809</span>          metrics[0]++;<a name="line.3809"></a>
+<span class="sourceLineNo">3810</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3810"></a>
+<span class="sourceLineNo">3811</span>        }<a name="line.3811"></a>
+<span class="sourceLineNo">3812</span>      } else if (m instanceof Delete) {<a name="line.3812"></a>
+<span class="sourceLineNo">3813</span>        Delete curDel = (Delete) m;<a name="line.3813"></a>
+<span class="sourceLineNo">3814</span>        if (curDel.getFamilyCellMap().isEmpty()) {<a name="line.3814"></a>
+<span class="sourceLineNo">3815</span>          // handle deleting a row case<a name="line.3815"></a>
+<span class="sourceLineNo">3816</span>          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.<a name="line.3816"></a>
+<span class="sourceLineNo">3817</span>          // Can this be avoided?<a name="line.3817"></a>
+<span class="sourceLineNo">3818</span>          region.prepareDelete(curDel);<a name="line.3818"></a>
+<span class="sourceLineNo">3819</span>        }<a name="line.3819"></a>
+<span class="sourceLineNo">3820</span>        if (region.coprocessorHost.preDelete(curDel, walEdit, m.getDurability())) {<a name="line.3820"></a>
+<span class="sourceLineNo">3821</span>          // pre hook says skip this Delete<a name="line.3821"></a>
+<span class="sourceLineNo">3822</span>          // mark as success and skip in doMiniBatchMutation<a name="line.3822"></a>
+<span class="sourceLineNo">3823</span>          metrics[1]++;<a name="line.3823"></a>
+<span class="sourceLineNo">3824</span>          retCodeDetails[index] = OperationStatus.SUCCESS;<a name="line.3824"></a>
+<span class="sourceLineNo">3825</span>        }<a name="line.3825"></a>
+<span class="sourceLineNo">3826</span>      } else {<a name="line.3826"></a>
+<span class="sourceLineNo">3827</span>        String msg = "Put/Delete mutations only supported in a batch";<a name="line.3827"></a>
+<span class="sourceLineNo">3828</span>        // In case of passing Append mutations along with the Puts and Deletes in batchMutate<a name="line.3828"></a>
+<span class="sourceLineNo">3829</span>        // mark the operation return code as failure so that it will not be considered in<a name="line.3829"></a>
+<span class="sourceLineNo">3830</span>        // the doMiniBatchMutation<a name="line.3830"></a>
+<span class="sourceLineNo">3831</span>        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);<a name="line.3831"></a>
+<span class="sourceLineNo">3832</span><a name="line.3832"></a>
+<span class="sourceLineNo">3833</span>        if (isAtomic()) { // fail, atomic means all or none<a name="line.3833"></a>
+<span class="sourceLineNo">3834</span>          throw new IOException(msg);<a name="line.3834"></a>
+<span class="sourceLineNo">3835</span>        }<a name="line.3835"></a>
+<span class="sourceLineNo">3836</span>      }<a name="line.3836"></a>
+<span class="sourceLineNo">3837</span>    }<a name="line.3837"></a>
+<span class="sourceLineNo">3838</span><a name="line.3838"></a>
+<span class="sourceLineNo">3839</span>    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3839"></a>
+<span class="sourceLineNo">3840</span>        final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {<a name="line.3840"></a>
+<span class="sourceLineNo">3841</span>      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {<a name="line.3841"></a>
+<span class="sourceLineNo">3842</span>        // we pass (i - firstIndex) below since the call expects a relative index<a name="line.3842"></a>
+<span class="sourceLineNo">3843</span>        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);<a name="line.3843"></a>
+<span class="sourceLineNo">3844</span>        if (cpMutations == null) {<a name="line.3844"></a>
+<span class="sourceLineNo">3845</span>          return true;<a name="line.3845"></a>
+<span class="sourceLineNo">3846</span>        }<a name="line.3846"></a>
+<span class="sourceLineNo">3847</span>        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.<a name="line.3847"></a>
+<span class="sourceLineNo">3848</span>        Mutation mutation = getMutation(i);<a name="line.3848"></a>
+<span class="sourceLineNo">3849</span>        for (Mutation cpMutation : cpMutations) {<a name="line.3849"></a>
+<span class="sourceLineNo">3850</span>          this.checkAndPrepareMutation(cpMutation, timestamp);<a name="line.3850"></a>
 <span class="sourceLineNo">3851</span><a name="line.3851"></a>
-<span class="sourceLineNo">3852</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3852"></a>
-<span class="sourceLineNo">3853</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3853"></a>
-<span class="sourceLineNo">3854</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3854"></a>
-<span class="sourceLineNo">3855</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3855"></a>
-<span class="sourceLineNo">3856</span>          // will get added to the memStore later<a name="line.3856"></a>
-<span class="sourceLineNo">3857</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3857"></a>
-<span class="sourceLineNo">3858</span><a name="line.3858"></a>
-<span class="sourceLineNo">3859</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3859"></a>
-<span class="sourceLineNo">3860</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3860"></a>
-<span class="sourceLineNo">3861</span>          // cells of returned mutation.<a name="line.3861"></a>
-<span class="sourceLineNo">3862</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3862"></a>
-<span class="sourceLineNo">3863</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3863"></a>
-<span class="sourceLineNo">3864</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3864"></a>
-<span class="sourceLineNo">3865</span>            }<a name="line.3865"></a>
-<span class="sourceLineNo">3866</span>          }<a name="line.3866"></a>
-<span class="sourceLineNo">3867</span>        }<a name="line.3867"></a>
-<span class="sourceLineNo">3868</span>        return true;<a name="line.3868"></a>
-<span class="sourceLineNo">3869</span>      });<a name="line.3869"></a>
-<span class="sourceLineNo">3870</span>    }<a name="line.3870"></a>
-<span class="sourceLineNo">3871</span><a name="line.3871"></a>
-<span class="sourceLineNo">3872</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3872"></a>
-<span class="sourceLineNo">3873</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3873"></a>
-<span class="sourceLineNo">3874</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3874"></a>
-<span class="sourceLineNo">3875</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3875"></a>
-<span class="sourceLineNo">3876</span>        if (cells == null) {<a name="line.3876"></a>
-<span class="sourceLineNo">3877</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3877"></a>
-<span class="sourceLineNo">3878</span>        } else {<a name="line.3878"></a>
-<span class="sourceLineNo">3879</span>          cells.addAll(entry.getValue());<a name="line.3879"></a>
-<span class="sourceLineNo">3880</span>        }<a name="line.3880"></a>
-<span class="sourceLineNo">3881</span>      }<a name="line.3881"></a>
-<span class="sourceLineNo">3882</span>    }<a name="line.3882"></a>
-<span class="sourceLineNo">3883</span>  }<a name="line.3883"></a>
-<span class="sourceLineNo">3884</span><a name="line.3884"></a>
-<span class="sourceLineNo">3885</span>  /**<a name="line.3885"></a>
-<span class="sourceLineNo">3886</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3886"></a>
-<span class="sourceLineNo">3887</span>   * of the logic is same.<a name="line.3887"></a>
-<span class="sourceLineNo">3888</span>   */<a name="line.3888"></a>
-<span class="sourceLineNo">3889</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3889"></a>
-<span class="sourceLineNo">3890</span>    private long origLogSeqNum = 0;<a name="line.3890"></a>
-<span class="sourceLineNo">3891</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3891"></a>
-<span class="sourceLineNo">3892</span>        long origLogSeqNum) {<a name="line.3892"></a>
-<span class="sourceLineNo">3893</span>      super(region, operations);<a name="line.3893"></a>
-<span class="sourceLineNo">3894</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3894"></a>
-<span class="sourceLineNo">3895</span>    }<a name="line.3895"></a>
-<span class="sourceLineNo">3896</span><a name="line.3896"></a>
-<span class="sourceLineNo">3897</span>    @Override<a name="line.3897"></a>
-<span class="sourceLineNo">3898</span>    public Mutation getMutation(int index) {<a name="line.3898"></a>
-<span class="sourceLineNo">3899</span>      return this.operations[index].mutation;<a name="line.3899"></a>
-<span class="sourceLineNo">3900</span>    }<a name="line.3900"></a>
-<span class="sourceLineNo">3901</span><a name="line.3901"></a>
-<span class="sourceLineNo">3902</span>    @Override<a name="line.3902"></a>
-<span class="sourceLineNo">3903</span>    public long getNonceGroup(int index) {<a name="line.3903"></a>
-<span class="sourceLineNo">3904</span>      return this.operations[index].nonceGroup;<a name="line.3904"></a>
-<span class="sourceLineNo">3905</span>    }<a name="line.3905"></a>
-<span class="sourceLineNo">3906</span><a name="line.3906"></a>
-<span class="sourceLineNo">3907</span>    @Override<a name="line.3907"></a>
-<span class="sourceLineNo">3908</span>    public long getNonce(int index) {<a name="line.3908"></a>
-<span class="sourceLineNo">3909</span>      return this.operations[index].nonce;<a name="line.3909"></a>
-<span class="sourceLineNo">3910</span>    }<a name="line.3910"></a>
-<span class="sourceLineNo">3911</span><a name="line.3911"></a>
-<span class="sourceLineNo">3912</span>    @Override<a name="line.3912"></a>
-<span class="sourceLineNo">3913</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3913"></a>
-<span class="sourceLineNo">3914</span>      return null;<a name="line.3914"></a>
-<span class="sourceLineNo">3915</span>    }<a name="line.3915"></a>
-<span class="sourceLineNo">3916</span><a name="line.3916"></a>
-<span class="sourceLineNo">3917</span>    @Override<a name="line.3917"></a>
-<span class="sourceLineNo">3918</span>    public boolean isInReplay() {<a name="line.3918"></a>
-<span class="sourceLineNo">3919</span>      return true;<a name="line.3919"></a>
-<span class="sourceLineNo">3920</span>    }<a name="line.3920"></a>
-<span class="sourceLineNo">3921</span><a name="line.3921"></a>
-<span class="sourceLineNo">3922</span>    @Override<a name="line.3922"></a>
-<span class="sourceLineNo">3923</span>    public long getOrigLogSeqNum() {<a name="line.3923"></a>
-<span class="sourceLineNo">3924</span>      return this.origLogSeqNum;<a name="line.3924"></a>
-<span class="sourceLineNo">3925</span>    }<a name="line.3925"></a>
-<span class="sourceLineNo">3926</span><a name="line.3926"></a>
-<span class="sourceLineNo">3927</span>    @Override<a name="line.3927"></a>
-<span class="sourceLineNo">3928</span>    public void startRegionOperation() throws IOException {<a name="line.3928"></a>
-<span class="sourceLineNo">3929</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3929"></a>
-<span class="sourceLineNo">3930</span>    }<a name="line.3930"></a>
-<span class="sourceLineNo">3931</span><a name="line.3931"></a>
-<span class="sourceLineNo">3932</span>    @Override<a name="line.3932"></a>
-<span class="sourceLineNo">3933</span>    public void closeRegionOperation() throws IOException {<a name="line.3933"></a>
-<span class="sourceLineNo">3934</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3934"></a>
-<span class="sourceLineNo">3935</span>    }<a name="line.3935"></a>
-<span class="sourceLineNo">3936</span><a name="line.3936"></a>
-<span class="sourceLineNo">3937</span>    /**<a name="line.3937"></a>
-<span class="sourceLineNo">3938</span>     * During replay, there could exist column families which are removed between region server<a name="line.3938"></a>
-<span class="sourceLineNo">3939</span>     * failure and replay<a name="line.3939"></a>
-<span class="sourceLineNo">3940</span>     */<a name="line.3940"></a>
-<span class="sourceLineNo">3941</span>    @Override<a name="line.3941"></a>
-<span class="sourceLineNo">3942</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3942"></a>
-<span class="sourceLineNo">3943</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3943"></a>
-<span class="sourceLineNo">3944</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3944"></a>
-<span class="sourceLineNo">3945</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3945"></a>
-<span class="sourceLineNo">3946</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3946"></a>
-<span class="sourceLineNo">3947</span>          if (nonExistentList == null) {<a name="line.3947"></a>
-<span class="sourceLineNo">3948</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3948"></a>
-<span class="sourceLineNo">3949</span>          }<a name="line.3949"></a>
-<span class="sourceLineNo">3950</span>          nonExistentList.add(family);<a name="line.3950"></a>
-<span class="sourceLineNo">3951</span>        }<a name="line.3951"></a>
-<span class="sourceLineNo">3952</span>      }<a name="line.3952"></a>
-<span class="sourceLineNo">3953</span>      if (nonExistentList != null) {<a name="line.3953"></a>
-<span class="sourceLineNo">3954</span>        for (byte[] family : nonExistentList) {<a name="line.3954"></a>
-<span class="sourceLineNo">3955</span>          // Perhaps schema was changed between crash and replay<a name="line.3955"></a>
-<span class="sourceLineNo">3956</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3956"></a>
-<span class="sourceLineNo">3957</span>          familyCellMap.remove(family);<a name="line.3957"></a>
-<span class="sourceLineNo">3958</span>        }<a name="line.3958"></a>
-<span class="sourceLineNo">3959</span>      }<a name="line.3959"></a>
-<span class="sourceLineNo">3960</span>    }<a name="line.3960"></a>
-<span class="sourceLineNo">3961</span><a name="line.3961"></a>
-<span class="sourceLineNo">3962</span>    @Override<a name="line.3962"></a>
-<span class="sourceLineNo">3963</span>    public void checkAndPrepare() throws IOException {<a name="line.3963"></a>
-<span class="sourceLineNo">3964</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3964"></a>
-<span class="sourceLineNo">3965</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3965"></a>
-<span class="sourceLineNo">3966</span>        checkAndPrepareMutation(index, now);<a name="line.3966"></a>
-<span class="sourceLineNo">3967</span>        return true;<a name="line.3967"></a>
-<span class="sourceLineNo">3968</span>      });<a name="line.3968"></a>
-<span class="sourceLineNo">3969</span>    }<a name="line.3969"></a>
-<span class="sourceLineNo">3970</span><a name="line.3970"></a>
-<span class="sourceLineNo">3971</span>    @Override<a name="line.3971"></a>
-<span class="sourceLineNo">3972</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3972"></a>
-<span class="sourceLineNo">3973</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3973"></a>
-<span class="sourceLineNo">3974</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3974"></a>
-<span class="sourceLineNo">3975</span>        // update cell count<a name="line.3975"></a>
-<span class="sourceLineNo">3976</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3976"></a>
-<span class="sourceLineNo">3977</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3977"></a>
-<span class="sourceLineNo">3978</span>        }<a name="line.3978"></a>
-<span class="sourceLineNo">3979</span>        return true;<a name="line.3979"></a>
-<span class="sourceLineNo">3980</span>      });<a name="line.3980"></a>
-<span class="sourceLineNo">3981</span>    }<a name="line.3981"></a>
-<span class="sourceLineNo">3982</span><a name="line.3982"></a>
-<span class="sourceLineNo">3983</span>    @Override<a name="line.3983"></a>
-<span class="sourceLineNo">3984</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3984"></a>
-<span class="sourceLineNo">3985</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3985"></a>
-<span class="sourceLineNo">3986</span>        throws IOException {<a name="line.3986"></a>
-<span class="sourceLineNo">3987</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3987"></a>
-<span class="sourceLineNo">3988</span>      return writeEntry;<a name="line.3988"></a>
-<span class="sourceLineNo">3989</span>    }<a name="line.3989"></a>
-<span class="sourceLineNo">3990</span><a name="line.3990"></a>
-<span class="sourceLineNo">3991</span>    @Override<a name="line.3991"></a>
-<span class="sourceLineNo">3992</span>    public void completeMiniBatchOperations(<a name="line.3992"></a>
-<span class="sourceLineNo">3993</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3993"></a>
-<span class="sourceLineNo">3994</span>        throws IOException {<a name="line.3994"></a>
-<span class="sourceLineNo">3995</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3995"></a>
-<span class="sourceLineNo">3996</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3996"></a>
-<span class="sourceLineNo">3997</span>    }<a name="line.3997"></a>
-<span class="sourceLineNo">3998</span>  }<a name="line.3998"></a>
-<span class="sourceLineNo">3999</span><a name="line.3999"></a>
-<span class="sourceLineNo">4000</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4000"></a>
-<span class="sourceLineNo">4001</span>      throws IOException {<a name="line.4001"></a>
-<span class="sourceLineNo">4002</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4002"></a>
-<span class="sourceLineNo">4003</span>  }<a name="line.4003"></a>
-<span class="sourceLineNo">4004</span><a name="line.4004"></a>
-<span class="sourceLineNo">4005</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4005"></a>
-<span class="sourceLineNo">4006</span>      long nonce) throws IOException {<a name="line.4006"></a>
-<span class="sourceLineNo">4007</span>    // As it stands, this is used for 3 things<a name="line.4007"></a>
-<span class="sourceLineNo">4008</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4008"></a>
-<span class="sourceLineNo">4009</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4009"></a>
-<span class="sourceLineNo">4010</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4010"></a>
-<span class="sourceLineNo">4011</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4011"></a>
-<span class="sourceLineNo">4012</span>  }<a name="line.4012"></a>
-<span class="sourceLineNo">4013</span><a name="line.4013"></a>
-<span class="sourceLineNo">4014</span>  @Override<a name="line.4014"></a>
-<span class="sourceLineNo">4015</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4015"></a>
-<span class="sourceLineNo">4016</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4016"></a>
-<span class="sourceLineNo">4017</span>  }<a name="line.4017"></a>
-<span class="sourceLineNo">4018</span><a name="line.4018"></a>
-<span class="sourceLineNo">4019</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4019"></a>
-<span class="sourceLineNo">4020</span>      throws IOException {<a name="line.4020"></a>
-<span class="sourceLineNo">4021</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4021"></a>
-<span class="sourceLineNo">4022</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4022"></a>
-<span class="sourceLineNo">4023</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4023"></a>
-<span class="sourceLineNo">4024</span>      // since they are coming out of order<a name="line.4024"></a>
-<span class="sourceLineNo">4025</span>      if (LOG.isTraceEnabled()) {<a name="line.4025"></a>
-<span class="sourceLineNo">4026</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4026"></a>
-<span class="sourceLineNo">4027</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4027"></a>
-<span class="sourceLineNo">4028</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4028"></a>
-<span class="sourceLineNo">4029</span>        for (MutationReplay mut : mutations) {<a name="line.4029"></a>
-<span class="sourceLineNo">4030</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4030"></a>
-<span class="sourceLineNo">4031</span>        }<a name="line.4031"></a>
-<span class="sourceLineNo">4032</span>      }<a name="line.4032"></a>
-<span class="sourceLineNo">4033</span><a name="line.4033"></a>
-<span class="sourceLineNo">4034</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4034"></a>
-<span class="sourceLineNo">4035</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4035"></a>
-<span class="sourceLineNo">4036</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4036"></a>
-<span class="sourceLineNo">4037</span>      }<a name="line.4037"></a>
-<span class="sourceLineNo">4038</span>      return statuses;<a name="line.4038"></a>
-<span class="sourceLineNo">4039</span>    }<a name="line.4039"></a>
-<span class="sourceLineNo">4040</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4040"></a>
-<span class="sourceLineNo">4041</span>  }<a name="line.4041"></a>
-<span class="sourceLineNo">4042</span><a name="line.4042"></a>
-<span class="sourceLineNo">4043</span>  /**<a name="line.4043"></a>
-<span class="sourceLineNo">4044</span>   * Perform a batch of mutations.<a name="line.4044"></a>
-<span class="sourceLineNo">4045</span>   *<a name="line.4045"></a>
-<span class="sourceLineNo">4046</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4046"></a>
-<span class="sourceLineNo">4047</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4047"></a>
-<span class="sourceLineNo">4048</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4048"></a>
-<span class="sourceLineNo">4049</span>   *<a name="line.4049"></a>
-<span class="sourceLineNo">4050</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4050"></a>
-<span class="sourceLineNo">4051</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4051"></a>
-<span class="sourceLineNo">4052</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4052"></a>
-<span class="sourceLineNo">4053</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4053"></a>
-<span class="sourceLineNo">4054</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4054"></a>
-<span class="sourceLineNo">4055</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4055"></a>
-<span class="sourceLineNo">4056</span>   * are overridden by derived classes to implement special behavior.<a name="line.4056"></a>
-<span class="sourceLineNo">4057</span>   *<a name="line.4057"></a>
-<span class="sourceLineNo">4058</span>   * @param batchOp contains the list of mutations<a name="line.4058"></a>
-<span class="sourceLineNo">4059</span>   * @return an array of OperationStatus which internally contains the<a name="line.4059"></a>
-<span class="sourceLineNo">4060</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4060"></a>
-<span class="sourceLineNo">4061</span>   * @throws IOException if an IO problem is encountered<a name="line.4061"></a>
-<span class="sourceLineNo">4062</span>   */<a name="line.4062"></a>
-<span class="sourceLineNo">4063</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4063"></a>
-<span class="sourceLineNo">4064</span>    boolean initialized = false;<a name="line.4064"></a>
-<span class="sourceLineNo">4065</span>    batchOp.startRegionOperation();<a name="line.4065"></a>
-<span class="sourceLineNo">4066</span>    try {<a name="line.4066"></a>
-<span class="sourceLineNo">4067</span>      while (!batchOp.isDone()) {<a name="line.4067"></a>
-<span class="sourceLineNo">4068</span>        if (!batchOp.isInReplay()) {<a name="line.4068"></a>
-<span class="sourceLineNo">4069</span>          checkReadOnly();<a name="line.4069"></a>
-<span class="sourceLineNo">4070</span>        }<a name="line.4070"></a>
-<span class="sourceLineNo">4071</span>        checkResources();<a name="line.4071"></a>
-<span class="sourceLineNo">4072</span><a name="line.4072"></a>
-<span class="sourceLineNo">4073</span>        if (!initialized) {<a name="line.4073"></a>
-<span class="sourceLineNo">4074</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4074"></a>
-<span class="sourceLineNo">4075</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4075"></a>
-<span class="sourceLineNo">4076</span>          // prePut()/ preDelete() hooks<a name="line.4076"></a>
-<span class="sourceLineNo">4077</span>          batchOp.checkAndPrepare();<a name="line.4077"></a>
-<span class="sourceLineNo">4078</span>          initialized = true;<a name="line.4078"></a>
-<span class="sourceLineNo">4079</span>        }<a name="line.4079"></a>
-<span class="sourceLineNo">4080</span>        doMiniBatchMutate(batchOp);<a name="line.4080"></a>
-<span class="sourceLineNo">4081</span>        requestFlushIfNeeded();<a name="line.4081"></a>
-<span class="sourceLineNo">4082</span>      }<a name="line.4082"></a>
-<span class="sourceLineNo">4083</span>    } finally {<a name="line.4083"></a>
-<span class="sourceLineNo">4084</span>      batchOp.closeRegionOperation();<a name="line.4084"></a>
-<span class="sourceLineNo">4085</span>    }<a name="line.4085"></a>
-<span class="sourceLineNo">4086</span>    return batchOp.retCodeDetails;<a name="line.4086"></a>
-<span class="sourceLineNo">4087</span>  }<a name="line.4087"></a>
-<span class="sourceLineNo">4088</span><a name="line.4088"></a>
-<span class="sourceLineNo">4089</span>  /**<a name="line.4089"></a>
-<span class="sourceLineNo">4090</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4090"></a>
-<span class="sourceLineNo">4091</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4091"></a>
-<span class="sourceLineNo">4092</span>   * about by applying {@code batchOp}.<a name="line.4092"></a>
-<span class="sourceLineNo">4093</span>   */<a name="line.4093"></a>
-<span class="sourceLineNo">4094</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4094"></a>
-<span class="sourceLineNo">4095</span>    boolean success = false;<a name="line.4095"></a>
-<span class="sourceLineNo">4096</span>    WALEdit walEdit = null;<a name="line.4096"></a>
-<span class="sourceLineNo">4097</span>    WriteEntry writeEntry = null;<a name="line.4097"></a>
-<span class="sourceLineNo">4098</span>    boolean locked = false;<a name="line.4098"></a>
-<span class="sourceLineNo">4099</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4099"></a>
-<span class="sourceLineNo">4100</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4100"></a>
-<span class="sourceLineNo">4101</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4101"></a>
-<span class="sourceLineNo">4102</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4102"></a>
-<span class="sourceLineNo">4103</span>    try {<a name="line.4103"></a>
-<span class="sourceLineNo">4104</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4104"></a>
-<span class="sourceLineNo">4105</span>      // locked rows<a name="line.4105"></a>
-<span class="sourceLineNo">4106</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4106"></a>
-<span class="sourceLineNo">4107</span><a name="line.4107"></a>
-<span class="sourceLineNo">4108</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4108"></a>
-<span class="sourceLineNo">4109</span>      // Ensure we acquire at least one.<a name="line.4109"></a>
-<span class="sourceLineNo">4110</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4110"></a>
-<span class="sourceLineNo">4111</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4111"></a>
-<span class="sourceLineNo">4112</span>        return;<a name="line.4112"></a>
-<span class="sourceLineNo">4113</span>      }<a name="line.4113"></a>
-<span class="sourceLineNo">4114</span><a name="line.4114"></a>
-<span class="sourceLineNo">4115</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4115"></a>
-<span class="sourceLineNo">4116</span>      locked = true;<a name="line.4116"></a>
+<span class="sourceLineNo">3852</span>          // Acquire row locks. If not, the whole batch will fail.<a name="line.3852"></a>
+<span class="sourceLineNo">3853</span>          acquiredRowLocks.add(region.getRowLockInternal(cpMutation.getRow(), true, null));<a name="line.3853"></a>
+<span class="sourceLineNo">3854</span><a name="line.3854"></a>
+<span class="sourceLineNo">3855</span>          // Returned mutations from coprocessor correspond to the Mutation at index i. We can<a name="line.3855"></a>
+<span class="sourceLineNo">3856</span>          // directly add the cells from those mutations to the familyMaps of this mutation.<a name="line.3856"></a>
+<span class="sourceLineNo">3857</span>          Map&lt;byte[], List&lt;Cell&gt;&gt; cpFamilyMap = cpMutation.getFamilyCellMap();<a name="line.3857"></a>
+<span class="sourceLineNo">3858</span>          region.rewriteCellTags(cpFamilyMap, mutation);<a name="line.3858"></a>
+<span class="sourceLineNo">3859</span>          // will get added to the memStore later<a name="line.3859"></a>
+<span class="sourceLineNo">3860</span>          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);<a name="line.3860"></a>
+<span class="sourceLineNo">3861</span><a name="line.3861"></a>
+<span class="sourceLineNo">3862</span>          // The durability of returned mutation is replaced by the corresponding mutation.<a name="line.3862"></a>
+<span class="sourceLineNo">3863</span>          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the<a name="line.3863"></a>
+<span class="sourceLineNo">3864</span>          // cells of returned mutation.<a name="line.3864"></a>
+<span class="sourceLineNo">3865</span>          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {<a name="line.3865"></a>
+<span class="sourceLineNo">3866</span>            for (List&lt;Cell&gt; cells : cpFamilyMap.values()) {<a name="line.3866"></a>
+<span class="sourceLineNo">3867</span>              miniBatchOp.addCellCount(cells.size());<a name="line.3867"></a>
+<span class="sourceLineNo">3868</span>            }<a name="line.3868"></a>
+<span class="sourceLineNo">3869</span>          }<a name="line.3869"></a>
+<span class="sourceLineNo">3870</span>        }<a name="line.3870"></a>
+<span class="sourceLineNo">3871</span>        return true;<a name="line.3871"></a>
+<span class="sourceLineNo">3872</span>      });<a name="line.3872"></a>
+<span class="sourceLineNo">3873</span>    }<a name="line.3873"></a>
+<span class="sourceLineNo">3874</span><a name="line.3874"></a>
+<span class="sourceLineNo">3875</span>    private void mergeFamilyMaps(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap,<a name="line.3875"></a>
+<span class="sourceLineNo">3876</span>        Map&lt;byte[], List&lt;Cell&gt;&gt; toBeMerged) {<a name="line.3876"></a>
+<span class="sourceLineNo">3877</span>      for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; entry : toBeMerged.entrySet()) {<a name="line.3877"></a>
+<span class="sourceLineNo">3878</span>        List&lt;Cell&gt; cells = familyMap.get(entry.getKey());<a name="line.3878"></a>
+<span class="sourceLineNo">3879</span>        if (cells == null) {<a name="line.3879"></a>
+<span class="sourceLineNo">3880</span>          familyMap.put(entry.getKey(), entry.getValue());<a name="line.3880"></a>
+<span class="sourceLineNo">3881</span>        } else {<a name="line.3881"></a>
+<span class="sourceLineNo">3882</span>          cells.addAll(entry.getValue());<a name="line.3882"></a>
+<span class="sourceLineNo">3883</span>        }<a name="line.3883"></a>
+<span class="sourceLineNo">3884</span>      }<a name="line.3884"></a>
+<span class="sourceLineNo">3885</span>    }<a name="line.3885"></a>
+<span class="sourceLineNo">3886</span>  }<a name="line.3886"></a>
+<span class="sourceLineNo">3887</span><a name="line.3887"></a>
+<span class="sourceLineNo">3888</span>  /**<a name="line.3888"></a>
+<span class="sourceLineNo">3889</span>   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most<a name="line.3889"></a>
+<span class="sourceLineNo">3890</span>   * of the logic is same.<a name="line.3890"></a>
+<span class="sourceLineNo">3891</span>   */<a name="line.3891"></a>
+<span class="sourceLineNo">3892</span>  static class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {<a name="line.3892"></a>
+<span class="sourceLineNo">3893</span>    private long origLogSeqNum = 0;<a name="line.3893"></a>
+<span class="sourceLineNo">3894</span>    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,<a name="line.3894"></a>
+<span class="sourceLineNo">3895</span>        long origLogSeqNum) {<a name="line.3895"></a>
+<span class="sourceLineNo">3896</span>      super(region, operations);<a name="line.3896"></a>
+<span class="sourceLineNo">3897</span>      this.origLogSeqNum = origLogSeqNum;<a name="line.3897"></a>
+<span class="sourceLineNo">3898</span>    }<a name="line.3898"></a>
+<span class="sourceLineNo">3899</span><a name="line.3899"></a>
+<span class="sourceLineNo">3900</span>    @Override<a name="line.3900"></a>
+<span class="sourceLineNo">3901</span>    public Mutation getMutation(int index) {<a name="line.3901"></a>
+<span class="sourceLineNo">3902</span>      return this.operations[index].mutation;<a name="line.3902"></a>
+<span class="sourceLineNo">3903</span>    }<a name="line.3903"></a>
+<span class="sourceLineNo">3904</span><a name="line.3904"></a>
+<span class="sourceLineNo">3905</span>    @Override<a name="line.3905"></a>
+<span class="sourceLineNo">3906</span>    public long getNonceGroup(int index) {<a name="line.3906"></a>
+<span class="sourceLineNo">3907</span>      return this.operations[index].nonceGroup;<a name="line.3907"></a>
+<span class="sourceLineNo">3908</span>    }<a name="line.3908"></a>
+<span class="sourceLineNo">3909</span><a name="line.3909"></a>
+<span class="sourceLineNo">3910</span>    @Override<a name="line.3910"></a>
+<span class="sourceLineNo">3911</span>    public long getNonce(int index) {<a name="line.3911"></a>
+<span class="sourceLineNo">3912</span>      return this.operations[index].nonce;<a name="line.3912"></a>
+<span class="sourceLineNo">3913</span>    }<a name="line.3913"></a>
+<span class="sourceLineNo">3914</span><a name="line.3914"></a>
+<span class="sourceLineNo">3915</span>    @Override<a name="line.3915"></a>
+<span class="sourceLineNo">3916</span>    public Mutation[] getMutationsForCoprocs() {<a name="line.3916"></a>
+<span class="sourceLineNo">3917</span>      return null;<a name="line.3917"></a>
+<span class="sourceLineNo">3918</span>    }<a name="line.3918"></a>
+<span class="sourceLineNo">3919</span><a name="line.3919"></a>
+<span class="sourceLineNo">3920</span>    @Override<a name="line.3920"></a>
+<span class="sourceLineNo">3921</span>    public boolean isInReplay() {<a name="line.3921"></a>
+<span class="sourceLineNo">3922</span>      return true;<a name="line.3922"></a>
+<span class="sourceLineNo">3923</span>    }<a name="line.3923"></a>
+<span class="sourceLineNo">3924</span><a name="line.3924"></a>
+<span class="sourceLineNo">3925</span>    @Override<a name="line.3925"></a>
+<span class="sourceLineNo">3926</span>    public long getOrigLogSeqNum() {<a name="line.3926"></a>
+<span class="sourceLineNo">3927</span>      return this.origLogSeqNum;<a name="line.3927"></a>
+<span class="sourceLineNo">3928</span>    }<a name="line.3928"></a>
+<span class="sourceLineNo">3929</span><a name="line.3929"></a>
+<span class="sourceLineNo">3930</span>    @Override<a name="line.3930"></a>
+<span class="sourceLineNo">3931</span>    public void startRegionOperation() throws IOException {<a name="line.3931"></a>
+<span class="sourceLineNo">3932</span>      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3932"></a>
+<span class="sourceLineNo">3933</span>    }<a name="line.3933"></a>
+<span class="sourceLineNo">3934</span><a name="line.3934"></a>
+<span class="sourceLineNo">3935</span>    @Override<a name="line.3935"></a>
+<span class="sourceLineNo">3936</span>    public void closeRegionOperation() throws IOException {<a name="line.3936"></a>
+<span class="sourceLineNo">3937</span>      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);<a name="line.3937"></a>
+<span class="sourceLineNo">3938</span>    }<a name="line.3938"></a>
+<span class="sourceLineNo">3939</span><a name="line.3939"></a>
+<span class="sourceLineNo">3940</span>    /**<a name="line.3940"></a>
+<span class="sourceLineNo">3941</span>     * During replay, there could exist column families which are removed between region server<a name="line.3941"></a>
+<span class="sourceLineNo">3942</span>     * failure and replay<a name="line.3942"></a>
+<span class="sourceLineNo">3943</span>     */<a name="line.3943"></a>
+<span class="sourceLineNo">3944</span>    @Override<a name="line.3944"></a>
+<span class="sourceLineNo">3945</span>    protected void checkAndPreparePut(Put p) throws IOException {<a name="line.3945"></a>
+<span class="sourceLineNo">3946</span>      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();<a name="line.3946"></a>
+<span class="sourceLineNo">3947</span>      List&lt;byte[]&gt; nonExistentList = null;<a name="line.3947"></a>
+<span class="sourceLineNo">3948</span>      for (byte[] family : familyCellMap.keySet()) {<a name="line.3948"></a>
+<span class="sourceLineNo">3949</span>        if (!region.htableDescriptor.hasColumnFamily(family)) {<a name="line.3949"></a>
+<span class="sourceLineNo">3950</span>          if (nonExistentList == null) {<a name="line.3950"></a>
+<span class="sourceLineNo">3951</span>            nonExistentList = new ArrayList&lt;&gt;();<a name="line.3951"></a>
+<span class="sourceLineNo">3952</span>          }<a name="line.3952"></a>
+<span class="sourceLineNo">3953</span>          nonExistentList.add(family);<a name="line.3953"></a>
+<span class="sourceLineNo">3954</span>        }<a name="line.3954"></a>
+<span class="sourceLineNo">3955</span>      }<a name="line.3955"></a>
+<span class="sourceLineNo">3956</span>      if (nonExistentList != null) {<a name="line.3956"></a>
+<span class="sourceLineNo">3957</span>        for (byte[] family : nonExistentList) {<a name="line.3957"></a>
+<span class="sourceLineNo">3958</span>          // Perhaps schema was changed between crash and replay<a name="line.3958"></a>
+<span class="sourceLineNo">3959</span>          LOG.info("No family for " + Bytes.toString(family) + " omit from reply.");<a name="line.3959"></a>
+<span class="sourceLineNo">3960</span>          familyCellMap.remove(family);<a name="line.3960"></a>
+<span class="sourceLineNo">3961</span>        }<a name="line.3961"></a>
+<span class="sourceLineNo">3962</span>      }<a name="line.3962"></a>
+<span class="sourceLineNo">3963</span>    }<a name="line.3963"></a>
+<span class="sourceLineNo">3964</span><a name="line.3964"></a>
+<span class="sourceLineNo">3965</span>    @Override<a name="line.3965"></a>
+<span class="sourceLineNo">3966</span>    public void checkAndPrepare() throws IOException {<a name="line.3966"></a>
+<span class="sourceLineNo">3967</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.3967"></a>
+<span class="sourceLineNo">3968</span>      visitBatchOperations(true, this.size(), (int index) -&gt; {<a name="line.3968"></a>
+<span class="sourceLineNo">3969</span>        checkAndPrepareMutation(index, now);<a name="line.3969"></a>
+<span class="sourceLineNo">3970</span>        return true;<a name="line.3970"></a>
+<span class="sourceLineNo">3971</span>      });<a name="line.3971"></a>
+<span class="sourceLineNo">3972</span>    }<a name="line.3972"></a>
+<span class="sourceLineNo">3973</span><a name="line.3973"></a>
+<span class="sourceLineNo">3974</span>    @Override<a name="line.3974"></a>
+<span class="sourceLineNo">3975</span>    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,<a name="line.3975"></a>
+<span class="sourceLineNo">3976</span>        long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.3976"></a>
+<span class="sourceLineNo">3977</span>      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {<a name="line.3977"></a>
+<span class="sourceLineNo">3978</span>        // update cell count<a name="line.3978"></a>
+<span class="sourceLineNo">3979</span>        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {<a name="line.3979"></a>
+<span class="sourceLineNo">3980</span>          miniBatchOp.addCellCount(cells.size());<a name="line.3980"></a>
+<span class="sourceLineNo">3981</span>        }<a name="line.3981"></a>
+<span class="sourceLineNo">3982</span>        return true;<a name="line.3982"></a>
+<span class="sourceLineNo">3983</span>      });<a name="line.3983"></a>
+<span class="sourceLineNo">3984</span>    }<a name="line.3984"></a>
+<span class="sourceLineNo">3985</span><a name="line.3985"></a>
+<span class="sourceLineNo">3986</span>    @Override<a name="line.3986"></a>
+<span class="sourceLineNo">3987</span>    public WriteEntry writeMiniBatchOperationsToMemStore(<a name="line.3987"></a>
+<span class="sourceLineNo">3988</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3988"></a>
+<span class="sourceLineNo">3989</span>        throws IOException {<a name="line.3989"></a>
+<span class="sourceLineNo">3990</span>      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());<a name="line.3990"></a>
+<span class="sourceLineNo">3991</span>      return writeEntry;<a name="line.3991"></a>
+<span class="sourceLineNo">3992</span>    }<a name="line.3992"></a>
+<span class="sourceLineNo">3993</span><a name="line.3993"></a>
+<span class="sourceLineNo">3994</span>    @Override<a name="line.3994"></a>
+<span class="sourceLineNo">3995</span>    public void completeMiniBatchOperations(<a name="line.3995"></a>
+<span class="sourceLineNo">3996</span>        final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)<a name="line.3996"></a>
+<span class="sourceLineNo">3997</span>        throws IOException {<a name="line.3997"></a>
+<span class="sourceLineNo">3998</span>      super.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.3998"></a>
+<span class="sourceLineNo">3999</span>      region.mvcc.advanceTo(getOrigLogSeqNum());<a name="line.3999"></a>
+<span class="sourceLineNo">4000</span>    }<a name="line.4000"></a>
+<span class="sourceLineNo">4001</span>  }<a name="line.4001"></a>
+<span class="sourceLineNo">4002</span><a name="line.4002"></a>
+<span class="sourceLineNo">4003</span>  public OperationStatus[] batchMutate(Mutation[] mutations, long nonceGroup, long nonce)<a name="line.4003"></a>
+<span class="sourceLineNo">4004</span>      throws IOException {<a name="line.4004"></a>
+<span class="sourceLineNo">4005</span>    return batchMutate(mutations, false, nonceGroup, nonce);<a name="line.4005"></a>
+<span class="sourceLineNo">4006</span>  }<a name="line.4006"></a>
+<span class="sourceLineNo">4007</span><a name="line.4007"></a>
+<span class="sourceLineNo">4008</span>  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,<a name="line.4008"></a>
+<span class="sourceLineNo">4009</span>      long nonce) throws IOException {<a name="line.4009"></a>
+<span class="sourceLineNo">4010</span>    // As it stands, this is used for 3 things<a name="line.4010"></a>
+<span class="sourceLineNo">4011</span>    //  * batchMutate with single mutation - put/delete, separate or from checkAndMutate.<a name="line.4011"></a>
+<span class="sourceLineNo">4012</span>    //  * coprocessor calls (see ex. BulkDeleteEndpoint).<a name="line.4012"></a>
+<span class="sourceLineNo">4013</span>    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...<a name="line.4013"></a>
+<span class="sourceLineNo">4014</span>    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));<a name="line.4014"></a>
+<span class="sourceLineNo">4015</span>  }<a name="line.4015"></a>
+<span class="sourceLineNo">4016</span><a name="line.4016"></a>
+<span class="sourceLineNo">4017</span>  @Override<a name="line.4017"></a>
+<span class="sourceLineNo">4018</span>  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {<a name="line.4018"></a>
+<span class="sourceLineNo">4019</span>    return batchMutate(mutations, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.4019"></a>
+<span class="sourceLineNo">4020</span>  }<a name="line.4020"></a>
+<span class="sourceLineNo">4021</span><a name="line.4021"></a>
+<span class="sourceLineNo">4022</span>  public OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId)<a name="line.4022"></a>
+<span class="sourceLineNo">4023</span>      throws IOException {<a name="line.4023"></a>
+<span class="sourceLineNo">4024</span>    if (!RegionReplicaUtil.isDefaultReplica(getRegionInfo())<a name="line.4024"></a>
+<span class="sourceLineNo">4025</span>        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4025"></a>
+<span class="sourceLineNo">4026</span>      // if it is a secondary replica we should ignore these entries silently<a name="line.4026"></a>
+<span class="sourceLineNo">4027</span>      // since they are coming out of order<a name="line.4027"></a>
+<span class="sourceLineNo">4028</span>      if (LOG.isTraceEnabled()) {<a name="line.4028"></a>
+<span class="sourceLineNo">4029</span>        LOG.trace(getRegionInfo().getEncodedName() + " : "<a name="line.4029"></a>
+<span class="sourceLineNo">4030</span>          + "Skipping " + mutations.length + " mutations with replaySeqId=" + replaySeqId<a name="line.4030"></a>
+<span class="sourceLineNo">4031</span>          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);<a name="line.4031"></a>
+<span class="sourceLineNo">4032</span>        for (MutationReplay mut : mutations) {<a name="line.4032"></a>
+<span class="sourceLineNo">4033</span>          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);<a name="line.4033"></a>
+<span class="sourceLineNo">4034</span>        }<a name="line.4034"></a>
+<span class="sourceLineNo">4035</span>      }<a name="line.4035"></a>
+<span class="sourceLineNo">4036</span><a name="line.4036"></a>
+<span class="sourceLineNo">4037</span>      OperationStatus[] statuses = new OperationStatus[mutations.length];<a name="line.4037"></a>
+<span class="sourceLineNo">4038</span>      for (int i = 0; i &lt; statuses.length; i++) {<a name="line.4038"></a>
+<span class="sourceLineNo">4039</span>        statuses[i] = OperationStatus.SUCCESS;<a name="line.4039"></a>
+<span class="sourceLineNo">4040</span>      }<a name="line.4040"></a>
+<span class="sourceLineNo">4041</span>      return statuses;<a name="line.4041"></a>
+<span class="sourceLineNo">4042</span>    }<a name="line.4042"></a>
+<span class="sourceLineNo">4043</span>    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));<a name="line.4043"></a>
+<span class="sourceLineNo">4044</span>  }<a name="line.4044"></a>
+<span class="sourceLineNo">4045</span><a name="line.4045"></a>
+<span class="sourceLineNo">4046</span>  /**<a name="line.4046"></a>
+<span class="sourceLineNo">4047</span>   * Perform a batch of mutations.<a name="line.4047"></a>
+<span class="sourceLineNo">4048</span>   *<a name="line.4048"></a>
+<span class="sourceLineNo">4049</span>   * It supports only Put and Delete mutations and will ignore other types passed. Operations in<a name="line.4049"></a>
+<span class="sourceLineNo">4050</span>   * a batch are stored with highest durability specified of for all operations in a batch,<a name="line.4050"></a>
+<span class="sourceLineNo">4051</span>   * except for {@link Durability#SKIP_WAL}.<a name="line.4051"></a>
+<span class="sourceLineNo">4052</span>   *<a name="line.4052"></a>
+<span class="sourceLineNo">4053</span>   * &lt;p&gt;This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with<a name="line.4053"></a>
+<span class="sourceLineNo">4054</span>   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[], long, long)} with<a name="line.4054"></a>
+<span class="sourceLineNo">4055</span>   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch<a name="line.4055"></a>
+<span class="sourceLineNo">4056</span>   * and mutation batch is very similar, lot of code is shared by providing generic methods in<a name="line.4056"></a>
+<span class="sourceLineNo">4057</span>   * base class {@link BatchOperation}. The logic for this method and<a name="line.4057"></a>
+<span class="sourceLineNo">4058</span>   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which<a name="line.4058"></a>
+<span class="sourceLineNo">4059</span>   * are overridden by derived classes to implement special behavior.<a name="line.4059"></a>
+<span class="sourceLineNo">4060</span>   *<a name="line.4060"></a>
+<span class="sourceLineNo">4061</span>   * @param batchOp contains the list of mutations<a name="line.4061"></a>
+<span class="sourceLineNo">4062</span>   * @return an array of OperationStatus which internally contains the<a name="line.4062"></a>
+<span class="sourceLineNo">4063</span>   *         OperationStatusCode and the exceptionMessage if any.<a name="line.4063"></a>
+<span class="sourceLineNo">4064</span>   * @throws IOException if an IO problem is encountered<a name="line.4064"></a>
+<span class="sourceLineNo">4065</span>   */<a name="line.4065"></a>
+<span class="sourceLineNo">4066</span>  OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4066"></a>
+<span class="sourceLineNo">4067</span>    boolean initialized = false;<a name="line.4067"></a>
+<span class="sourceLineNo">4068</span>    batchOp.startRegionOperation();<a name="line.4068"></a>
+<span class="sourceLineNo">4069</span>    try {<a name="line.4069"></a>
+<span class="sourceLineNo">4070</span>      while (!batchOp.isDone()) {<a name="line.4070"></a>
+<span class="sourceLineNo">4071</span>        if (!batchOp.isInReplay()) {<a name="line.4071"></a>
+<span class="sourceLineNo">4072</span>          checkReadOnly();<a name="line.4072"></a>
+<span class="sourceLineNo">4073</span>        }<a name="line.4073"></a>
+<span class="sourceLineNo">4074</span>        checkResources();<a name="line.4074"></a>
+<span class="sourceLineNo">4075</span><a name="line.4075"></a>
+<span class="sourceLineNo">4076</span>        if (!initialized) {<a name="line.4076"></a>
+<span class="sourceLineNo">4077</span>          this.writeRequestsCount.add(batchOp.size());<a name="line.4077"></a>
+<span class="sourceLineNo">4078</span>          // validate and prepare batch for write, for MutationBatchOperation it also calls CP<a name="line.4078"></a>
+<span class="sourceLineNo">4079</span>          // prePut()/ preDelete() hooks<a name="line.4079"></a>
+<span class="sourceLineNo">4080</span>          batchOp.checkAndPrepare();<a name="line.4080"></a>
+<span class="sourceLineNo">4081</span>          initialized = true;<a name="line.4081"></a>
+<span class="sourceLineNo">4082</span>        }<a name="line.4082"></a>
+<span class="sourceLineNo">4083</span>        doMiniBatchMutate(batchOp);<a name="line.4083"></a>
+<span class="sourceLineNo">4084</span>        requestFlushIfNeeded();<a name="line.4084"></a>
+<span class="sourceLineNo">4085</span>      }<a name="line.4085"></a>
+<span class="sourceLineNo">4086</span>    } finally {<a name="line.4086"></a>
+<span class="sourceLineNo">4087</span>      batchOp.closeRegionOperation();<a name="line.4087"></a>
+<span class="sourceLineNo">4088</span>    }<a name="line.4088"></a>
+<span class="sourceLineNo">4089</span>    return batchOp.retCodeDetails;<a name="line.4089"></a>
+<span class="sourceLineNo">4090</span>  }<a name="line.4090"></a>
+<span class="sourceLineNo">4091</span><a name="line.4091"></a>
+<span class="sourceLineNo">4092</span>  /**<a name="line.4092"></a>
+<span class="sourceLineNo">4093</span>   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[], long, long)}<a name="line.4093"></a>
+<span class="sourceLineNo">4094</span>   * In here we also handle replay of edits on region recover. Also gets change in size brought<a name="line.4094"></a>
+<span class="sourceLineNo">4095</span>   * about by applying {@code batchOp}.<a name="line.4095"></a>
+<span class="sourceLineNo">4096</span>   */<a name="line.4096"></a>
+<span class="sourceLineNo">4097</span>  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {<a name="line.4097"></a>
+<span class="sourceLineNo">4098</span>    boolean success = false;<a name="line.4098"></a>
+<span class="sourceLineNo">4099</span>    WALEdit walEdit = null;<a name="line.4099"></a>
+<span class="sourceLineNo">4100</span>    WriteEntry writeEntry = null;<a name="line.4100"></a>
+<span class="sourceLineNo">4101</span>    boolean locked = false;<a name="line.4101"></a>
+<span class="sourceLineNo">4102</span>    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)<a name="line.4102"></a>
+<span class="sourceLineNo">4103</span>    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;<a name="line.4103"></a>
+<span class="sourceLineNo">4104</span>    /** Keep track of the locks we hold so we can release them in finally clause */<a name="line.4104"></a>
+<span class="sourceLineNo">4105</span>    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());<a name="line.4105"></a>
+<span class="sourceLineNo">4106</span>    try {<a name="line.4106"></a>
+<span class="sourceLineNo">4107</span>      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with<a name="line.4107"></a>
+<span class="sourceLineNo">4108</span>      // locked rows<a name="line.4108"></a>
+<span class="sourceLineNo">4109</span>      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);<a name="line.4109"></a>
+<span class="sourceLineNo">4110</span><a name="line.4110"></a>
+<span class="sourceLineNo">4111</span>      // We've now grabbed as many mutations off the list as we can<a name="line.4111"></a>
+<span class="sourceLineNo">4112</span>      // Ensure we acquire at least one.<a name="line.4112"></a>
+<span class="sourceLineNo">4113</span>      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {<a name="line.4113"></a>
+<span class="sourceLineNo">4114</span>        // Nothing to put/delete -- an exception in the above such as NoSuchColumnFamily?<a name="line.4114"></a>
+<span class="sourceLineNo">4115</span>        return;<a name="line.4115"></a>
+<span class="sourceLineNo">4116</span>      }<a name="line.4116"></a>
 <span class="sourceLineNo">4117</span><a name="line.4117"></a>
-<span class="sourceLineNo">4118</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4118"></a>
-<span class="sourceLineNo">4119</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4119"></a>
-<span class="sourceLineNo">4120</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4120"></a>
-<span class="sourceLineNo">4121</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4121"></a>
-<span class="sourceLineNo">4122</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4122"></a>
-<span class="sourceLineNo">4123</span><a name="line.4123"></a>
-<span class="sourceLineNo">4124</span>      // STEP 3. Build WAL edit<a name="line.4124"></a>
-<span class="sourceLineNo">4125</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4125"></a>
+<span class="sourceLineNo">4118</span>      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());<a name="line.4118"></a>
+<span class="sourceLineNo">4119</span>      locked = true;<a name="line.4119"></a>
+<span class="sourceLineNo">4120</span><a name="line.4120"></a>
+<span class="sourceLineNo">4121</span>      // STEP 2. Update mini batch of all operations in progress with  LATEST_TIMESTAMP timestamp<a name="line.4121"></a>
+<span class="sourceLineNo">4122</span>      // We should record the timestamp only after we have acquired the rowLock,<a name="line.4122"></a>
+<span class="sourceLineNo">4123</span>      // otherwise, newer puts/deletes are not guaranteed to have a newer timestamp<a name="line.4123"></a>
+<span class="sourceLineNo">4124</span>      long now = EnvironmentEdgeManager.currentTime();<a name="line.4124"></a>
+<span class="sourceLineNo">4125</span>      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);<a name="line.4125"></a>
 <span class="sourceLineNo">4126</span><a name="line.4126"></a>
-<span class="sourceLineNo">4127</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4127"></a>
-<span class="sourceLineNo">4128</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4128"></a>
-<span class="sourceLineNo">4129</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4129"></a>
-<span class="sourceLineNo">4130</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4130"></a>
-<span class="sourceLineNo">4131</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4131"></a>
-<span class="sourceLineNo">4132</span><a name="line.4132"></a>
-<span class="sourceLineNo">4133</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4133"></a>
-<span class="sourceLineNo">4134</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4134"></a>
-<span class="sourceLineNo">4135</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4135"></a>
-<span class="sourceLineNo">4136</span>        }<a name="line.4136"></a>
-<span class="sourceLineNo">4137</span><a name="line.4137"></a>
-<span class="sourceLineNo">4138</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4138"></a>
-<span class="sourceLineNo">4139</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4139"></a>
-<span class="sourceLineNo">4140</span>          mvcc.complete(writeEntry);<a name="line.4140"></a>
-<span class="sourceLineNo">4141</span>          writeEntry = null;<a name="line.4141"></a>
-<span class="sourceLineNo">4142</span>        }<a name="line.4142"></a>
-<span class="sourceLineNo">4143</span>      }<a name="line.4143"></a>
-<span class="sourceLineNo">4144</span><a name="line.4144"></a>
-<span class="sourceLineNo">4145</span>      // STEP 5. Write back to memStore<a name="line.4145"></a>
-<span class="sourceLineNo">4146</span>      // NOTE: writeEntry can be null here<a name="line.4146"></a>
-<span class="sourceLineNo">4147</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4147"></a>
-<span class="sourceLineNo">4148</span><a name="line.4148"></a>
-<span class="sourceLineNo">4149</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4149"></a>
-<span class="sourceLineNo">4150</span>      // complete mvcc for last writeEntry<a name="line.4150"></a>
-<span class="sourceLineNo">4151</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4151"></a>
-<span class="sourceLineNo">4152</span>      writeEntry = null;<a name="line.4152"></a>
-<span class="sourceLineNo">4153</span>      success = true;<a name="line.4153"></a>
-<span class="sourceLineNo">4154</span>    } finally {<a name="line.4154"></a>
-<span class="sourceLineNo">4155</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4155"></a>
-<span class="sourceLineNo">4156</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4156"></a>
-<span class="sourceLineNo">4157</span><a name="line.4157"></a>
-<span class="sourceLineNo">4158</span>      if (locked) {<a name="line.4158"></a>
-<span class="sourceLineNo">4159</span>        this.updatesLock.readLock().unlock();<a name="line.4159"></a>
-<span class="sourceLineNo">4160</span>      }<a name="line.4160"></a>
-<span class="sourceLineNo">4161</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4161"></a>
-<span class="sourceLineNo">4162</span><a name="line.4162"></a>
-<span class="sourceLineNo">4163</span>      final int finalLastIndexExclusive =<a name="line.4163"></a>
-<span class="sourceLineNo">4164</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4164"></a>
-<span class="sourceLineNo">4165</span>      final boolean finalSuccess = success;<a name="line.4165"></a>
-<span class="sourceLineNo">4166</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4166"></a>
-<span class="sourceLineNo">4167</span>        batchOp.retCodeDetails[i] =<a name="line.4167"></a>
-<span class="sourceLineNo">4168</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4168"></a>
-<span class="sourceLineNo">4169</span>        return true;<a name="line.4169"></a>
-<span class="sourceLineNo">4170</span>      });<a name="line.4170"></a>
-<span class="sourceLineNo">4171</span><a name="line.4171"></a>
-<span class="sourceLineNo">4172</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4172"></a>
-<span class="sourceLineNo">4173</span><a name="line.4173"></a>
-<span class="sourceLineNo">4174</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4174"></a>
-<span class="sourceLineNo">4175</span>    }<a name="line.4175"></a>
-<span class="sourceLineNo">4176</span>  }<a name="line.4176"></a>
-<span class="sourceLineNo">4177</span><a name="line.4177"></a>
-<span class="sourceLineNo">4178</span>  /**<a name="line.4178"></a>
-<span class="sourceLineNo">4179</span>   * Returns effective durability from the passed durability and<a name="line.4179"></a>
-<span class="sourceLineNo">4180</span>   * the table descriptor.<a name="line.4180"></a>
-<span class="sourceLineNo">4181</span>   */<a name="line.4181"></a>
-<span class="sourceLineNo">4182</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4182"></a>
-<span class="sourceLineNo">4183</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4183"></a>
-<span class="sourceLineNo">4184</span>  }<a name="line.4184"></a>
-<span class="sourceLineNo">4185</span><a name="line.4185"></a>
-<span class="sourceLineNo">4186</span>  @Override<a name="line.4186"></a>
-<span class="sourceLineNo">4187</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4187"></a>
-<span class="sourceLineNo">4188</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4188"></a>
-<span class="sourceLineNo">4189</span>    checkMutationType(mutation, row);<a name="line.4189"></a>
-<span class="sourceLineNo">4190</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4190"></a>
-<span class="sourceLineNo">4191</span>  }<a name="line.4191"></a>
-<span class="sourceLineNo">4192</span><a name="line.4192"></a>
-<span class="sourceLineNo">4193</span>  @Override<a name="line.4193"></a>
-<span class="sourceLineNo">4194</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4194"></a>
-<span class="sourceLineNo">4195</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4195"></a>
-<span class="sourceLineNo">4196</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4196"></a>
-<span class="sourceLineNo">4197</span>  }<a name="line.4197"></a>
-<span class="sourceLineNo">4198</span><a name="line.4198"></a>
-<span class="sourceLineNo">4199</span>  /**<a name="line.4199"></a>
-<span class="sourceLineNo">4200</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4200"></a>
-<span class="sourceLineNo">4201</span>   * switches in the few places where there is deviation.<a name="line.4201"></a>
-<span class="sourceLineNo">4202</span>   */<a name="line.4202"></a>
-<span class="sourceLineNo">4203</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4203"></a>
-<span class="sourceLineNo">4204</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4204"></a>
-<span class="sourceLineNo">4205</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4205"></a>
-<span class="sourceLineNo">4206</span>  throws IOException {<a name="line.4206"></a>
-<span class="sourceLineNo">4207</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4207"></a>
-<span class="sourceLineNo">4208</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4208"></a>
-<span class="sourceLineNo">4209</span>    // need these commented out checks.<a name="line.4209"></a>
-<span class="sourceLineNo">4210</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4210"></a>
-<span class="sourceLineNo">4211</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4211"></a>
-<span class="sourceLineNo">4212</span>    checkReadOnly();<a name="line.4212"></a>
-<span class="sourceLineNo">4213</span>    // TODO, add check for value length also move this check to the client<a name="line.4213"></a>
-<span class="sourceLineNo">4214</span>    checkResources();<a name="line.4214"></a>
-<span class="sourceLineNo">4215</span>    startRegionOperation();<a name="line.4215"></a>
-<span class="sourceLineNo">4216</span>    try {<a name="line.4216"></a>
-<span class="sourceLineNo">4217</span>      Get get = new Get(row);<a name="line.4217"></a>
-<span class="sourceLineNo">4218</span>      checkFamily(family);<a name="line.4218"></a>
-<span class="sourceLineNo">4219</span>      get.addColumn(family, qualifier);<a name="line.4219"></a>
-<span class="sourceLineNo">4220</span>      if (timeRange != null) {<a name="line.4220"></a>
-<span class="sourceLineNo">4221</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4221"></a>
-<span class="sourceLineNo">4222</span>      }<a name="line.4222"></a>
-<span class="sourceLineNo">4223</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4223"></a>
-<span class="sourceLineNo">4224</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4224"></a>
-<span class="sourceLineNo">4225</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4225"></a>
-<span class="sourceLineNo">4226</span>      try {<a name="line.4226"></a>
-<span class="sourceLineNo">4227</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4227"></a>
-<span class="sourceLineNo">4228</span>          // Call coprocessor.<a name="line.4228"></a>
-<span class="sourceLineNo">4229</span>          Boolean processed = null;<a name="line.4229"></a>
-<span class="sourceLineNo">4230</span>          if (mutation instanceof Put) {<a name="line.4230"></a>
-<span class="sourceLineNo">4231</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4231"></a>
-<span class="sourceLineNo">4232</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4232"></a>
-<span class="sourceLineNo">4233</span>          } else if (mutation instanceof Delete) {<a name="line.4233"></a>
-<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4234"></a>
-<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4235"></a>
-<span class="sourceLineNo">4236</span>          }<a name="line.4236"></a>
-<span class="sourceLineNo">4237</span>          if (processed != null) {<a name="line.4237"></a>
-<span class="sourceLineNo">4238</span>            return processed;<a name="line.4238"></a>
+<span class="sourceLineNo">4127</span>      // STEP 3. Build WAL edit<a name="line.4127"></a>
+<span class="sourceLineNo">4128</span>      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);<a name="line.4128"></a>
+<span class="sourceLineNo">4129</span><a name="line.4129"></a>
+<span class="sourceLineNo">4130</span>      // STEP 4. Append the WALEdits to WAL and sync.<a name="line.4130"></a>
+<span class="sourceLineNo">4131</span>      for(Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {<a name="line.4131"></a>
+<span class="sourceLineNo">4132</span>        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();<a name="line.4132"></a>
+<span class="sourceLineNo">4133</span>        walEdit = nonceKeyWALEditPair.getSecond();<a name="line.4133"></a>
+<span class="sourceLineNo">4134</span>        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();<a name="line.4134"></a>
+<span class="sourceLineNo">4135</span><a name="line.4135"></a>
+<span class="sourceLineNo">4136</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.4136"></a>
+<span class="sourceLineNo">4137</span>          writeEntry = doWALAppend(walEdit, batchOp.durability, batchOp.getClusterIds(), now,<a name="line.4137"></a>
+<span class="sourceLineNo">4138</span>              nonceKey.getNonceGroup(), nonceKey.getNonce(), batchOp.getOrigLogSeqNum());<a name="line.4138"></a>
+<span class="sourceLineNo">4139</span>        }<a name="line.4139"></a>
+<span class="sourceLineNo">4140</span><a name="line.4140"></a>
+<span class="sourceLineNo">4141</span>        // Complete mvcc for all but last writeEntry (for replay case)<a name="line.4141"></a>
+<span class="sourceLineNo">4142</span>        if (it.hasNext() &amp;&amp; writeEntry != null) {<a name="line.4142"></a>
+<span class="sourceLineNo">4143</span>          mvcc.complete(writeEntry);<a name="line.4143"></a>
+<span class="sourceLineNo">4144</span>          writeEntry = null;<a name="line.4144"></a>
+<span class="sourceLineNo">4145</span>        }<a name="line.4145"></a>
+<span class="sourceLineNo">4146</span>      }<a name="line.4146"></a>
+<span class="sourceLineNo">4147</span><a name="line.4147"></a>
+<span class="sourceLineNo">4148</span>      // STEP 5. Write back to memStore<a name="line.4148"></a>
+<span class="sourceLineNo">4149</span>      // NOTE: writeEntry can be null here<a name="line.4149"></a>
+<span class="sourceLineNo">4150</span>      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry);<a name="line.4150"></a>
+<span class="sourceLineNo">4151</span><a name="line.4151"></a>
+<span class="sourceLineNo">4152</span>      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and<a name="line.4152"></a>
+<span class="sourceLineNo">4153</span>      // complete mvcc for last writeEntry<a name="line.4153"></a>
+<span class="sourceLineNo">4154</span>      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);<a name="line.4154"></a>
+<span class="sourceLineNo">4155</span>      writeEntry = null;<a name="line.4155"></a>
+<span class="sourceLineNo">4156</span>      success = true;<a name="line.4156"></a>
+<span class="sourceLineNo">4157</span>    } finally {<a name="line.4157"></a>
+<span class="sourceLineNo">4158</span>      // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.4158"></a>
+<span class="sourceLineNo">4159</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.4159"></a>
+<span class="sourceLineNo">4160</span><a name="line.4160"></a>
+<span class="sourceLineNo">4161</span>      if (locked) {<a name="line.4161"></a>
+<span class="sourceLineNo">4162</span>        this.updatesLock.readLock().unlock();<a name="line.4162"></a>
+<span class="sourceLineNo">4163</span>      }<a name="line.4163"></a>
+<span class="sourceLineNo">4164</span>      releaseRowLocks(acquiredRowLocks);<a name="line.4164"></a>
+<span class="sourceLineNo">4165</span><a name="line.4165"></a>
+<span class="sourceLineNo">4166</span>      final int finalLastIndexExclusive =<a name="line.4166"></a>
+<span class="sourceLineNo">4167</span>          miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();<a name="line.4167"></a>
+<span class="sourceLineNo">4168</span>      final boolean finalSuccess = success;<a name="line.4168"></a>
+<span class="sourceLineNo">4169</span>      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {<a name="line.4169"></a>
+<span class="sourceLineNo">4170</span>        batchOp.retCodeDetails[i] =<a name="line.4170"></a>
+<span class="sourceLineNo">4171</span>            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;<a name="line.4171"></a>
+<span class="sourceLineNo">4172</span>        return true;<a name="line.4172"></a>
+<span class="sourceLineNo">4173</span>      });<a name="line.4173"></a>
+<span class="sourceLineNo">4174</span><a name="line.4174"></a>
+<span class="sourceLineNo">4175</span>      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);<a name="line.4175"></a>
+<span class="sourceLineNo">4176</span><a name="line.4176"></a>
+<span class="sourceLineNo">4177</span>      batchOp.nextIndexToProcess = finalLastIndexExclusive;<a name="line.4177"></a>
+<span class="sourceLineNo">4178</span>    }<a name="line.4178"></a>
+<span class="sourceLineNo">4179</span>  }<a name="line.4179"></a>
+<span class="sourceLineNo">4180</span><a name="line.4180"></a>
+<span class="sourceLineNo">4181</span>  /**<a name="line.4181"></a>
+<span class="sourceLineNo">4182</span>   * Returns effective durability from the passed durability and<a name="line.4182"></a>
+<span class="sourceLineNo">4183</span>   * the table descriptor.<a name="line.4183"></a>
+<span class="sourceLineNo">4184</span>   */<a name="line.4184"></a>
+<span class="sourceLineNo">4185</span>  protected Durability getEffectiveDurability(Durability d) {<a name="line.4185"></a>
+<span class="sourceLineNo">4186</span>    return d == Durability.USE_DEFAULT ? this.regionDurability : d;<a name="line.4186"></a>
+<span class="sourceLineNo">4187</span>  }<a name="line.4187"></a>
+<span class="sourceLineNo">4188</span><a name="line.4188"></a>
+<span class="sourceLineNo">4189</span>  @Override<a name="line.4189"></a>
+<span class="sourceLineNo">4190</span>  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4190"></a>
+<span class="sourceLineNo">4191</span>    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {<a name="line.4191"></a>
+<span class="sourceLineNo">4192</span>    checkMutationType(mutation, row);<a name="line.4192"></a>
+<span class="sourceLineNo">4193</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, null, mutation);<a name="line.4193"></a>
+<span class="sourceLineNo">4194</span>  }<a name="line.4194"></a>
+<span class="sourceLineNo">4195</span><a name="line.4195"></a>
+<span class="sourceLineNo">4196</span>  @Override<a name="line.4196"></a>
+<span class="sourceLineNo">4197</span>  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,<a name="line.4197"></a>
+<span class="sourceLineNo">4198</span>    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {<a name="line.4198"></a>
+<span class="sourceLineNo">4199</span>    return doCheckAndRowMutate(row, family, qualifier, op, comparator, timeRange, rm, null);<a name="line.4199"></a>
+<span class="sourceLineNo">4200</span>  }<a name="line.4200"></a>
+<span class="sourceLineNo">4201</span><a name="line.4201"></a>
+<span class="sourceLineNo">4202</span>  /**<a name="line.4202"></a>
+<span class="sourceLineNo">4203</span>   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has<a name="line.4203"></a>
+<span class="sourceLineNo">4204</span>   * switches in the few places where there is deviation.<a name="line.4204"></a>
+<span class="sourceLineNo">4205</span>   */<a name="line.4205"></a>
+<span class="sourceLineNo">4206</span>  private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier,<a name="line.4206"></a>
+<span class="sourceLineNo">4207</span>    CompareOperator op, ByteArrayComparable comparator, TimeRange timeRange,<a name="line.4207"></a>
+<span class="sourceLineNo">4208</span>    RowMutations rowMutations, Mutation mutation)<a name="line.4208"></a>
+<span class="sourceLineNo">4209</span>  throws IOException {<a name="line.4209"></a>
+<span class="sourceLineNo">4210</span>    // Could do the below checks but seems wacky with two callers only. Just comment out for now.<a name="line.4210"></a>
+<span class="sourceLineNo">4211</span>    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't<a name="line.4211"></a>
+<span class="sourceLineNo">4212</span>    // need these commented out checks.<a name="line.4212"></a>
+<span class="sourceLineNo">4213</span>    // if (rowMutations == null &amp;&amp; mutation == null) throw new DoNotRetryIOException("Both null");<a name="line.4213"></a>
+<span class="sourceLineNo">4214</span>    // if (rowMutations != null &amp;&amp; mutation != null) throw new DoNotRetryIOException("Both set");<a name="line.4214"></a>
+<span class="sourceLineNo">4215</span>    checkReadOnly();<a name="line.4215"></a>
+<span class="sourceLineNo">4216</span>    // TODO, add check for value length also move this check to the client<a name="line.4216"></a>
+<span class="sourceLineNo">4217</span>    checkResources();<a name="line.4217"></a>
+<span class="sourceLineNo">4218</span>    startRegionOperation();<a name="line.4218"></a>
+<span class="sourceLineNo">4219</span>    try {<a name="line.4219"></a>
+<span class="sourceLineNo">4220</span>      Get get = new Get(row);<a name="line.4220"></a>
+<span class="sourceLineNo">4221</span>      checkFamily(family);<a name="line.4221"></a>
+<span class="sourceLineNo">4222</span>      get.addColumn(family, qualifier);<a name="line.4222"></a>
+<span class="sourceLineNo">4223</span>      if (timeRange != null) {<a name="line.4223"></a>
+<span class="sourceLineNo">4224</span>        get.setTimeRange(timeRange.getMin(), timeRange.getMax());<a name="line.4224"></a>
+<span class="sourceLineNo">4225</span>      }<a name="line.4225"></a>
+<span class="sourceLineNo">4226</span>      // Lock row - note that doBatchMutate will relock this row if called<a name="line.4226"></a>
+<span class="sourceLineNo">4227</span>      checkRow(row, "doCheckAndRowMutate");<a name="line.4227"></a>
+<span class="sourceLineNo">4228</span>      RowLock rowLock = getRowLockInternal(get.getRow(), false, null);<a name="line.4228"></a>
+<span class="sourceLineNo">4229</span>      try {<a name="line.4229"></a>
+<span class="sourceLineNo">4230</span>        if (mutation != null &amp;&amp; this.getCoprocessorHost() != null) {<a name="line.4230"></a>
+<span class="sourceLineNo">4231</span>          // Call coprocessor.<a name="line.4231"></a>
+<span class="sourceLineNo">4232</span>          Boolean processed = null;<a name="line.4232"></a>
+<span class="sourceLineNo">4233</span>          if (mutation instanceof Put) {<a name="line.4233"></a>
+<span class="sourceLineNo">4234</span>            processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family,<a name="line.4234"></a>
+<span class="sourceLineNo">4235</span>                qualifier, op, comparator, (Put)mutation);<a name="line.4235"></a>
+<span class="sourceLineNo">4236</span>          } else if (mutation instanceof Delete) {<a name="line.4236"></a>
+<span class="sourceLineNo">4237</span>            processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family,<a name="line.4237"></a>
+<span class="sourceLineNo">4238</span>                qualifier, op, comparator, (Delete)mutation);<a name="line.4238"></a>
 <span class="sourceLineNo">4239</span>          }<a name="line.4239"></a>
-<span class="sourceLineNo">4240</span>        }<a name="line.4240"></a>
-<span class="sourceLineNo">4241</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4241"></a>
-<span class="sourceLineNo">4242</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4242"></a>
-<span class="sourceLineNo">4243</span>        // we'll get the latest on this row.<a name="line.4243"></a>
-<span class="sourceLineNo">4244</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4244"></a>
-<span class="sourceLineNo">4245</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4245"></a>
-<span class="sourceLineNo">4246</span>        boolean matches = false;<a name="line.4246"></a>
-<span class="sourceLineNo">4247</span>        long cellTs = 0;<a name="line.4247"></a>
-<span class="sourceLineNo">4248</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4248"></a>
-<span class="sourceLineNo">4249</span>          matches = true;<a name="line.4249"></a>
-<span class="sourceLineNo">4250</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4250"></a>
-<span class="sourceLineNo">4251</span>          matches = true;<a name="line.4251"></a>
-<span class="sourceLineNo">4252</span>          cellTs = result.get(0).getTimestamp();<a name="line.4252"></a>
-<span class="sourceLineNo">4253</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4253"></a>
-<span class="sourceLineNo">4254</span>          Cell kv = result.get(0);<a name="line.4254"></a>
-<span class="sourceLineNo">4255</span>          cellTs = kv.getTimestamp();<a name="line.4255"></a>
-<span class="sourceLineNo">4256</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4256"></a>
-<span class="sourceLineNo">4257</span>          matches = matches(op, compareResult);<a name="line.4257"></a>
-<span class="sourceLineNo">4258</span>        }<a name="line.4258"></a>
-<span class="sourceLineNo">4259</span>        // If matches put the new put or delete the new delete<a name="line.4259"></a>
-<span class="sourceLineNo">4260</span>        if (matches) {<a name="line.4260"></a>
-<span class="sourceLineNo">4261</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4261"></a>
-<span class="sourceLineNo">4262</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4262"></a>
-<span class="sourceLineNo">4263</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4263"></a>
-<span class="sourceLineNo">4264</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4264"></a>
-<span class="sourceLineNo">4265</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4265"></a>
-<span class="sourceLineNo">4266</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4266"></a>
-<span class="sourceLineNo">4267</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4267"></a>
-<span class="sourceLineNo">4268</span>          if (mutation != null) {<a name="line.4268"></a>
-<span class="sourceLineNo">4269</span>            if (mutation instanceof Put) {<a name="line.4269"></a>
-<span class="sourceLineNo">4270</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4270"></a>
-<span class="sourceLineNo">4271</span>            }<a name="line.4271"></a>
-<span class="sourceLineNo">4272</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4272"></a>
-<span class="sourceLineNo">4273</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4273"></a>
-<span class="sourceLineNo">4274</span>          } else {<a name="line.4274"></a>
-<span class="sourceLineNo">4275</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4275"></a>
-<span class="sourceLineNo">4276</span>              if (m instanceof Put) {<a name="line.4276"></a>
-<span class="sourceLineNo">4277</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4277"></a>
-<span class="sourceLineNo">4278</span>              }<a name="line.4278"></a>
-<span class="sourceLineNo">4279</span>            }<a name="line.4279"></a>
-<span class="sourceLineNo">4280</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4280"></a>
-<span class="sourceLineNo">4281</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4281"></a>
-<span class="sourceLineNo">4282</span>          }<a name="line.4282"></a>
-<span class="sourceLineNo">4283</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4283"></a>
-<span class="sourceLineNo">4284</span>          if (mutation != null) {<a name="line.4284"></a>
-<span class="sourceLineNo">4285</span>            doBatchMutate(mutation);<a name="line.4285"></a>
-<span class="sourceLineNo">4286</span>          } else {<a name="line.4286"></a>
-<span class="sourceLineNo">4287</span>            mutateRow(rowMutations);<a name="line.4287"></a>
-<span class="sourceLineNo">4288</span>          }<a name="line.4288"></a>
-<span class="sourceLineNo">4289</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4289"></a>
-<span class="sourceLineNo">4290</span>          return true;<a name="line.4290"></a>
-<span class="sourceLineNo">4291</span>        }<a name="line.4291"></a>
-<span class="sourceLineNo">4292</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4292"></a>
-<span class="sourceLineNo">4293</span>        return false;<a name="line.4293"></a>
-<span class="sourceLineNo">4294</span>      } finally {<a name="line.4294"></a>
-<span class="sourceLineNo">4295</span>        rowLock.release();<a name="line.4295"></a>
-<span class="sourceLineNo">4296</span>      }<a name="line.4296"></a>
-<span class="sourceLineNo">4297</span>    } finally {<a name="line.4297"></a>
-<span class="sourceLineNo">4298</span>      closeRegionOperation();<a name="line.4298"></a>
-<span class="sourceLineNo">4299</span>    }<a name="line.4299"></a>
-<span class="sourceLineNo">4300</span>  }<a name="line.4300"></a>
-<span class="sourceLineNo">4301</span><a name="line.4301"></a>
-<span class="sourceLineNo">4302</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4302"></a>
-<span class="sourceLineNo">4303</span>  throws DoNotRetryIOException {<a name="line.4303"></a>
-<span class="sourceLineNo">4304</span>    boolean isPut = mutation instanceof Put;<a name="line.4304"></a>
-<span class="sourceLineNo">4305</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4305"></a>
-<span class="sourceLineNo">4306</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4306"></a>
-<span class="sourceLineNo">4307</span>    }<a name="line.4307"></a>
-<span class="sourceLineNo">4308</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4308"></a>
-<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4309"></a>
+<span class="sourceLineNo">4240</span>          if (processed != null) {<a name="line.4240"></a>
+<span class="sourceLineNo">4241</span>            return processed;<a name="line.4241"></a>
+<span class="sourceLineNo">4242</span>          }<a name="line.4242"></a>
+<span class="sourceLineNo">4243</span>        }<a name="line.4243"></a>
+<span class="sourceLineNo">4244</span>        // NOTE: We used to wait here until mvcc caught up:  mvcc.await();<a name="line.4244"></a>
+<span class="sourceLineNo">4245</span>        // Supposition is that now all changes are done under row locks, then when we go to read,<a name="line.4245"></a>
+<span class="sourceLineNo">4246</span>        // we'll get the latest on this row.<a name="line.4246"></a>
+<span class="sourceLineNo">4247</span>        List&lt;Cell&gt; result = get(get, false);<a name="line.4247"></a>
+<span class="sourceLineNo">4248</span>        boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;<a name="line.4248"></a>
+<span class="sourceLineNo">4249</span>        boolean matches = false;<a name="line.4249"></a>
+<span class="sourceLineNo">4250</span>        long cellTs = 0;<a name="line.4250"></a>
+<span class="sourceLineNo">4251</span>        if (result.isEmpty() &amp;&amp; valueIsNull) {<a name="line.4251"></a>
+<span class="sourceLineNo">4252</span>          matches = true;<a name="line.4252"></a>
+<span class="sourceLineNo">4253</span>        } else if (result.size() &gt; 0 &amp;&amp; result.get(0).getValueLength() == 0 &amp;&amp; valueIsNull) {<a name="line.4253"></a>
+<span class="sourceLineNo">4254</span>          matches = true;<a name="line.4254"></a>
+<span class="sourceLineNo">4255</span>          cellTs = result.get(0).getTimestamp();<a name="line.4255"></a>
+<span class="sourceLineNo">4256</span>        } else if (result.size() == 1 &amp;&amp; !valueIsNull) {<a name="line.4256"></a>
+<span class="sourceLineNo">4257</span>          Cell kv = result.get(0);<a name="line.4257"></a>
+<span class="sourceLineNo">4258</span>          cellTs = kv.getTimestamp();<a name="line.4258"></a>
+<span class="sourceLineNo">4259</span>          int compareResult = PrivateCellUtil.compareValue(kv, comparator);<a name="line.4259"></a>
+<span class="sourceLineNo">4260</span>          matches = matches(op, compareResult);<a name="line.4260"></a>
+<span class="sourceLineNo">4261</span>        }<a name="line.4261"></a>
+<span class="sourceLineNo">4262</span>        // If matches put the new put or delete the new delete<a name="line.4262"></a>
+<span class="sourceLineNo">4263</span>        if (matches) {<a name="line.4263"></a>
+<span class="sourceLineNo">4264</span>          // We have acquired the row lock already. If the system clock is NOT monotonically<a name="line.4264"></a>
+<span class="sourceLineNo">4265</span>          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a<a name="line.4265"></a>
+<span class="sourceLineNo">4266</span>          // larger timestamp than what was observed via Get. doBatchMutate already does this, but<a name="line.4266"></a>
+<span class="sourceLineNo">4267</span>          // there is no way to pass the cellTs. See HBASE-14054.<a name="line.4267"></a>
+<span class="sourceLineNo">4268</span>          long now = EnvironmentEdgeManager.currentTime();<a name="line.4268"></a>
+<span class="sourceLineNo">4269</span>          long ts = Math.max(now, cellTs); // ensure write is not eclipsed<a name="line.4269"></a>
+<span class="sourceLineNo">4270</span>          byte[] byteTs = Bytes.toBytes(ts);<a name="line.4270"></a>
+<span class="sourceLineNo">4271</span>          if (mutation != null) {<a name="line.4271"></a>
+<span class="sourceLineNo">4272</span>            if (mutation instanceof Put) {<a name="line.4272"></a>
+<span class="sourceLineNo">4273</span>              updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);<a name="line.4273"></a>
+<span class="sourceLineNo">4274</span>            }<a name="line.4274"></a>
+<span class="sourceLineNo">4275</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4275"></a>
+<span class="sourceLineNo">4276</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4276"></a>
+<span class="sourceLineNo">4277</span>          } else {<a name="line.4277"></a>
+<span class="sourceLineNo">4278</span>            for (Mutation m: rowMutations.getMutations()) {<a name="line.4278"></a>
+<span class="sourceLineNo">4279</span>              if (m instanceof Put) {<a name="line.4279"></a>
+<span class="sourceLineNo">4280</span>                updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);<a name="line.4280"></a>
+<span class="sourceLineNo">4281</span>              }<a name="line.4281"></a>
+<span class="sourceLineNo">4282</span>            }<a name="line.4282"></a>
+<span class="sourceLineNo">4283</span>            // And else 'delete' is not needed since it already does a second get, and sets the<a name="line.4283"></a>
+<span class="sourceLineNo">4284</span>            // timestamp from get (see prepareDeleteTimestamps).<a name="line.4284"></a>
+<span class="sourceLineNo">4285</span>          }<a name="line.4285"></a>
+<span class="sourceLineNo">4286</span>          // All edits for the given row (across all column families) must happen atomically.<a name="line.4286"></a>
+<span class="sourceLineNo">4287</span>          if (mutation != null) {<a name="line.4287"></a>
+<span class="sourceLineNo">4288</span>            doBatchMutate(mutation);<a name="line.4288"></a>
+<span class="sourceLineNo">4289</span>          } else {<a name="line.4289"></a>
+<span class="sourceLineNo">4290</span>            mutateRow(rowMutations);<a name="line.4290"></a>
+<span class="sourceLineNo">4291</span>          }<a name="line.4291"></a>
+<span class="sourceLineNo">4292</span>          this.checkAndMutateChecksPassed.increment();<a name="line.4292"></a>
+<span class="sourceLineNo">4293</span>          return true;<a name="line.4293"></a>
+<span class="sourceLineNo">4294</span>        }<a name="line.4294"></a>
+<span class="sourceLineNo">4295</span>        this.checkAndMutateChecksFailed.increment();<a name="line.4295"></a>
+<span class="sourceLineNo">4296</span>        return false;<a name="line.4296"></a>
+<span class="sourceLineNo">4297</span>      } finally {<a name="line.4297"></a>
+<span class="sourceLineNo">4298</span>        rowLock.release();<a name="line.4298"></a>
+<span class="sourceLineNo">4299</span>      }<a name="line.4299"></a>
+<span class="sourceLineNo">4300</span>    } finally {<a name="line.4300"></a>
+<span class="sourceLineNo">4301</span>      closeRegionOperation();<a name="line.4301"></a>
+<span class="sourceLineNo">4302</span>    }<a name="line.4302"></a>
+<span class="sourceLineNo">4303</span>  }<a name="line.4303"></a>
+<span class="sourceLineNo">4304</span><a name="line.4304"></a>
+<span class="sourceLineNo">4305</span>  private void checkMutationType(final Mutation mutation, final byte [] row)<a name="line.4305"></a>
+<span class="sourceLineNo">4306</span>  throws DoNotRetryIOException {<a name="line.4306"></a>
+<span class="sourceLineNo">4307</span>    boolean isPut = mutation instanceof Put;<a name="line.4307"></a>
+<span class="sourceLineNo">4308</span>    if (!isPut &amp;&amp; !(mutation instanceof Delete)) {<a name="line.4308"></a>
+<span class="sourceLineNo">4309</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");<a name="line.4309"></a>
 <span class="sourceLineNo">4310</span>    }<a name="line.4310"></a>
-<span class="sourceLineNo">4311</span>  }<a name="line.4311"></a>
-<span class="sourceLineNo">4312</span><a name="line.4312"></a>
-<span class="sourceLineNo">4313</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4313"></a>
-<span class="sourceLineNo">4314</span>    boolean matches = false;<a name="line.4314"></a>
-<span class="sourceLineNo">4315</span>    switch (op) {<a name="line.4315"></a>
-<span class="sourceLineNo">4316</span>      case LESS:<a name="line.4316"></a>
-<span class="sourceLineNo">4317</span>        matches = compareResult &lt; 0;<a name="line.4317"></a>
-<span class="sourceLineNo">4318</span>        break;<a name="line.4318"></a>
-<span class="sourceLineNo">4319</span>      case LESS_OR_EQUAL:<a name="line.4319"></a>
-<span class="sourceLineNo">4320</span>        matches = compareResult &lt;= 0;<a name="line.4320"></a>
+<span class="sourceLineNo">4311</span>    if (!Bytes.equals(row, mutation.getRow())) {<a name="line.4311"></a>
+<span class="sourceLineNo">4312</span>      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");<a name="line.4312"></a>
+<span class="sourceLineNo">4313</span>    }<a name="line.4313"></a>
+<span class="sourceLineNo">4314</span>  }<a name="line.4314"></a>
+<span class="sourceLineNo">4315</span><a name="line.4315"></a>
+<span class="sourceLineNo">4316</span>  private boolean matches(final CompareOperator op, final int compareResult) {<a name="line.4316"></a>
+<span class="sourceLineNo">4317</span>    boolean matches = false;<a name="line.4317"></a>
+<span class="sourceLineNo">4318</span>    switch (op) {<a name="line.4318"></a>
+<span class="sourceLineNo">4319</span>      case LESS:<a name="line.4319"></a>
+<span class="sourceLineNo">4320</span>        matches = compareResult &lt; 0;<a name="line.4320"></a>
 <span class="sourceLineNo">4321</span>        break;<a name="line.4321"></a>
-<span class="sourceLineNo">4322</span>      case EQUAL:<a name="line.4322"></a>
-<span class="sourceLineNo">4323</span>        matches = compareResult == 0;<a name="line.4323"></a>
+<span class="sourceLineNo">4322</span>      case LESS_OR_EQUAL:<a name="line.4322"></a>
+<span class="sourceLineNo">4323</span>        matches = compareResult &lt;= 0;<a name="line.4323"></a>
 <span class="sourceLineNo">4324</span>        break;<a name="line.4324"></a>
-<span class="sourceLineNo">4325</span>      case NOT_EQUAL:<a name="line.4325"></a>
-<span class="sourceLineNo">4326</span>        matches = compareResult != 0;<a name="line.4326"></a>
+<span class="sourceLineNo">4325</span>      case EQUAL:<a name="line.4325"></a>
+<span class="sourceLineNo">4326</span>        matches = compareResult == 0;<a name="line.4326"></a>
 <span class="sourceLineNo">4327</span>        break;<a name="line.4327"></a>
-<span class="sourceLineNo">4328</span>      case GREATER_OR_EQUAL:<a name="line.4328"></a>
-<span class="sourceLineNo">4329</span>        matches = compareResult &gt;= 0;<a name="line.4329"></a>
+<span class="sourceLineNo">4328</span>      case NOT_EQUAL:<a name="line.4328"></a>
+<span class="sourceLineNo">4329</span>        matches = compareResult != 0;<a name="line.4329"></a>
 <span class="sourceLineNo">4330</span>        break;<a name="line.4330"></a>
-<span class="sourceLineNo">4331</span>      case GREATER:<a name="line.4331"></a>
-<span class="sourceLineNo">4332</span>        matches = compareResult &gt; 0;<a name="line.4332"></a>
+<span class="sourceLineNo">4331</span>      case GREATER_OR_EQUAL:<a name="line.4331"></a>
+<span class="sourceLineNo">4332</span>        matches = compareResult &gt;= 0;<a name="line.4332"></a>
 <span class="sourceLineNo">4333</span>        break;<a name="line.4333"></a>
-<span class="sourceLineNo">4334</span>      default:<a name="line.4334"></a>
-<span class="sourceLineNo">4335</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4335"></a>
-<span class="sourceLineNo">4336</span>    }<a name="line.4336"></a>
-<span class="sourceLineNo">4337</span>    return matches;<a name="line.4337"></a>
-<span class="sourceLineNo">4338</span>  }<a name="line.4338"></a>
-<span class="sourceLineNo">4339</span><a name="line.4339"></a>
-<span class="sourceLineNo">4340</span><a name="line.4340"></a>
-<span class="sourceLineNo">4341</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4341"></a>
-<span class="sourceLineNo">4342</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4342"></a>
-<span class="sourceLineNo">4343</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4343"></a>
-<span class="sourceLineNo">4344</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4344"></a>
-<span class="sourceLineNo">4345</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4345"></a>
-<span class="sourceLineNo">4346</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4346"></a>
-<span class="sourceLineNo">4347</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4347"></a>
-<span class="sourceLineNo">4348</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4348"></a>
-<span class="sourceLineNo">4349</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4349"></a>
-<span class="sourceLineNo">4350</span>    }<a name="line.4350"></a>
-<span class="sourceLineNo">4351</span>  }<a name="line.4351"></a>
-<span class="sourceLineNo">4352</span><a name="line.4352"></a>
-<span class="sourceLineNo">4353</span>  /**<a name="line.4353"></a>
-<span class="sourceLineNo">4354</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4354"></a>
-<span class="sourceLineNo">4355</span>   * working snapshot directory.<a name="line.4355"></a>
-<span class="sourceLineNo">4356</span>   *<a name="line.4356"></a>
-<span class="sourceLineNo">4357</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4357"></a>
-<span class="sourceLineNo">4358</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4358"></a>
-<span class="sourceLineNo">4359</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4359"></a>
-<span class="sourceLineNo">4360</span>   *<a name="line.4360"></a>
-<span class="sourceLineNo">4361</span>   * @param desc snapshot description object<a name="line.4361"></a>
-<span class="sourceLineNo">4362</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4362"></a>
-<span class="sourceLineNo">4363</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4363"></a>
-<span class="sourceLineNo">4364</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4364"></a>
-<span class="sourceLineNo">4365</span>   */<a name="line.4365"></a>
-<span class="sourceLineNo">4366</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4366"></a>
-<span class="sourceLineNo">4367</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4367"></a>
-<span class="sourceLineNo">4368</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4368"></a>
-<span class="sourceLineNo">4369</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4369"></a>
-<span class="sourceLineNo">4370</span><a name="line.4370"></a>
-<span class="sourceLineNo">4371</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4371"></a>
-<span class="sourceLineNo">4372</span>            snapshotDir, desc, exnSnare);<a name="line.4372"></a>
-<span class="sourceLineNo">4373</span>    manifest.addRegion(this);<a name="line.4373"></a>
-<span class="sourceLineNo">4374</span>  }<a name="line.4374"></a>
-<span class="sourceLineNo">4375</span><a name="line.4375"></a>
-<span class="sourceLineNo">4376</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4376"></a>
-<span class="sourceLineNo">4377</span>      throws IOException {<a name="line.4377"></a>
-<span class="sourceLineNo">4378</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4378"></a>
-<span class="sourceLineNo">4379</span>      if (cells == null) return;<a name="line.4379"></a>
-<span class="sourceLineNo">4380</span>      for (Cell cell : cells) {<a name="line.4380"></a>
-<span class="sourceLineNo">4381</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4381"></a>
-<span class="sourceLineNo">4382</span>      }<a name="line.4382"></a>
-<span class="sourceLineNo">4383</span>    }<a name="line.4383"></a>
-<span class="sourceLineNo">4384</span>  }<a name="line.4384"></a>
-<span class="sourceLineNo">4385</span><a name="line.4385"></a>
-<span class="sourceLineNo">4386</span>  /**<a name="line.4386"></a>
-<span class="sourceLineNo">4387</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4387"></a>
-<span class="sourceLineNo">4388</span>   * provided current timestamp.<a name="line.4388"></a>
-<span class="sourceLineNo">4389</span>   * @param cellItr<a name="line.4389"></a>
-<span class="sourceLineNo">4390</span>   * @param now<a name="line.4390"></a>
-<span class="sourceLineNo">4391</span>   */<a name="line.4391"></a>
-<span class="sourceLineNo">4392</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4392"></a>
-<span class="sourceLineNo">4393</span>      throws IOException {<a name="line.4393"></a>
-<span class="sourceLineNo">4394</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4394"></a>
-<span class="sourceLineNo">4395</span>      if (cells == null) continue;<a name="line.4395"></a>
-<span class="sourceLineNo">4396</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4396"></a>
-<span class="sourceLineNo">4397</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4397"></a>
-<span class="sourceLineNo">4398</span>      assert cells instanceof RandomAccess;<a name="line.4398"></a>
-<span class="sourceLineNo">4399</span>      int listSize = cells.size();<a name="line.4399"></a>
-<span class="sourceLineNo">4400</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4400"></a>
-<span class="sourceLineNo">4401</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4401"></a>
-<span class="sourceLineNo">4402</span>      }<a name="line.4402"></a>
-<span class="sourceLineNo">4403</span>    }<a name="line.4403"></a>
-<span class="sourceLineNo">4404</span>  }<a name="line.4404"></a>
-<span class="sourceLineNo">4405</span><a name="line.4405"></a>
-<span class="sourceLineNo">4406</span>  /**<a name="line.4406"></a>
-<span class="sourceLineNo">4407</span>   * Possibly rewrite incoming cell tags.<a name="line.4407"></a>
-<span class="sourceLineNo">4408</span>   */<a name="line.4408"></a>
-<span class="sourceLineNo">4409</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4409"></a>
-<span class="sourceLineNo">4410</span>    // Check if we have any work to do and early out otherwise<a name="line.4410"></a>
-<span class="sourceLineNo">4411</span>    // Update these checks as more logic is added here<a name="line.4411"></a>
-<span class="sourceLineNo">4412</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4412"></a>
-<span class="sourceLineNo">4413</span>      return;<a name="line.4413"></a>
-<span class="sourceLineNo">4414</span>    }<a name="line.4414"></a>
-<span class="sourceLineNo">4415</span><a name="line.4415"></a>
-<span class="sourceLineNo">4416</span>    // From this point we know we have some work to do<a name="line.4416"></a>
-<span class="sourceLineNo">4417</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4417"></a>
-<span class="sourceLineNo">4418</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4418"></a>
-<span class="sourceLineNo">4419</span>      assert cells instanceof RandomAccess;<a name="line.4419"></a>
-<span class="sourceLineNo">4420</span>      int listSize = cells.size();<a name="line.4420"></a>
-<span class="sourceLineNo">4421</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4421"></a>
-<span class="sourceLineNo">4422</span>        Cell cell = cells.get(i);<a name="line.4422"></a>
-<span class="sourceLineNo">4423</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4423"></a>
-<span class="sourceLineNo">4424</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4424"></a>
-<span class="sourceLineNo">4425</span>        // Rewrite the cell with the updated set of tags<a name="line.4425"></a>
-<span class="sourceLineNo">4426</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4426"></a>
-<span class="sourceLineNo">4427</span>      }<a name="line.4427"></a>
-<span class="sourceLineNo">4428</span>    }<a name="line.4428"></a>
-<span class="sourceLineNo">4429</span>  }<a name="line.4429"></a>
-<span class="sourceLineNo">4430</span><a name="line.4430"></a>
-<span class="sourceLineNo">4431</span>  /*<a name="line.4431"></a>
-<span class="sourceLineNo">4432</span>   * Check if resources to support an update.<a name="line.4432"></a>
-<span class="sourceLineNo">4433</span>   *<a name="line.4433"></a>
-<span class="sourceLineNo">4434</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4434"></a>
-<span class="sourceLineNo">4435</span>   * and expect client to retry using some kind of backoff<a name="line.4435"></a>
-<span class="sourceLineNo">4436</span>  */<a name="line.4436"></a>
-<span class="sourceLineNo">4437</span>  void checkResources() throws RegionTooBusyException {<a name="line.4437"></a>
-<span class="sourceLineNo">4438</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4438"></a>
-<span class="sourceLineNo">4439</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4439"></a>
-<span class="sourceLineNo">4440</span><a name="line.4440"></a>
-<span class="sourceLineNo">4441</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4441"></a>
-<span class="sourceLineNo">4442</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4442"></a>
-<span class="sourceLineNo">4443</span>      blockedRequestsCount.increment();<a name="line.4443"></a>
-<span class="sourceLineNo">4444</span>      requestFlush();<a name="line.4444"></a>
-<span class="sourceLineNo">4445</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4445"></a>
-<span class="sourceLineNo">4446</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4446"></a>
-<span class="sourceLineNo">4447</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4447"></a>
-<span class="sourceLineNo">4448</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4448"></a>
-<span class="sourceLineNo">4449</span>        ", regionName=" +<a name="line.4449"></a>
-<span class="sourceLineNo">4450</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4450"></a>
-<span class="sourceLineNo">4451</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4451"></a>
-<span class="sourceLineNo">4452</span>              this.getRegionServerServices().getServerName()));<a name="line.4452"></a>
-<span class="sourceLineNo">4453</span>    }<a name="line.4453"></a>
-<span class="sourceLineNo">4454</span>  }<a name="line.4454"></a>
-<span class="sourceLineNo">4455</span><a name="line.4455"></a>
-<span class="sourceLineNo">4456</span>  /**<a name="line.4456"></a>
-<span class="sourceLineNo">4457</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4457"></a>
-<span class="sourceLineNo">4458</span>   */<a name="line.4458"></a>
-<span class="sourceLineNo">4459</span>  protected void checkReadOnly() throws IOException {<a name="line.4459"></a>
-<span class="sourceLineNo">4460</span>    if (isReadOnly()) {<a name="line.4460"></a>
-<span class="sourceLineNo">4461</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4461"></a>
-<span class="sourceLineNo">4462</span>    }<a name="line.4462"></a>
-<span class="sourceLineNo">4463</span>  }<a name="line.4463"></a>
-<span class="sourceLineNo">4464</span><a name="line.4464"></a>
-<span class="sourceLineNo">4465</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4465"></a>
-<span class="sourceLineNo">4466</span>    if (!this.writestate.readsEnabled) {<a name="line.4466"></a>
-<span class="sourceLineNo">4467</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4467"></a>
-<span class="sourceLineNo">4468</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4468"></a>
-<span class="sourceLineNo">4469</span>    }<a name="line.4469"></a>
-<span class="sourceLineNo">4470</span>  }<a name="line.4470"></a>
-<span class="sourceLineNo">4471</span><a name="line.4471"></a>
-<span class="sourceLineNo">4472</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4472"></a>
-<span class="sourceLineNo">4473</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4473"></a>
-<span class="sourceLineNo">4474</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4474"></a>
-<span class="sourceLineNo">4475</span>    }<a name="line.4475"></a>
-<span class="sourceLineNo">4476</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4476"></a>
-<span class="sourceLineNo">4477</span>  }<a name="line.4477"></a>
-<span class="sourceLineNo">4478</span><a name="line.4478"></a>
-<span class="sourceLineNo">4479</span>  /**<a name="line.4479"></a>
-<span class="sourceLineNo">4480</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4480"></a>
-<span class="sourceLineNo">4481</span>   * &lt;p&gt;<a name="line.4481"></a>
-<span class="sourceLineNo">4482</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4482"></a>
-<span class="sourceLineNo">4483</span>   * @param edits Cell updates by column<a name="line.4483"></a>
-<span class="sourceLineNo">4484</span>   */<a name="line.4484"></a>
-<span class="sourceLineNo">4485</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4485"></a>
-<span class="sourceLineNo">4486</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4486"></a>
-<span class="sourceLineNo">4487</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4487"></a>
-<span class="sourceLineNo">4488</span><a name="line.4488"></a>
-<span class="sourceLineNo">4489</span>    familyMap.put(family, edits);<a name="line.4489"></a>
-<span class="sourceLineNo">4490</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4490"></a>
-<span class="sourceLineNo">4491</span>    doBatchMutate(p);<a name="line.4491"></a>
-<span class="sourceLineNo">4492</span>  }<a name="line.4492"></a>
-<span class="sourceLineNo">4493</span><a name="line.4493"></a>
-<span class="sourceLineNo">4494</span>  /**<a name="line.4494"></a>
-<span class="sourceLineNo">4495</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4495"></a>
-<span class="sourceLineNo">4496</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4496"></a>
-<span class="sourceLineNo">4497</span>   *          but that do not make sense otherwise.<a name="line.4497"></a>
-<span class="sourceLineNo">4498</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4498"></a>
-<span class="sourceLineNo">4499</span>   */<a name="line.4499"></a>
-<span class="sourceLineNo">4500</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4500"></a>
-<span class="sourceLineNo">4501</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4501"></a>
-<span class="sourceLineNo">4502</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4502"></a>
-<span class="sourceLineNo">4503</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4503"></a>
-<span class="sourceLineNo">4504</span>    if (upsert) {<a name="line.4504"></a>
-<span class="sourceLineNo">4505</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4505"></a>
-<span class="sourceLineNo">4506</span>    } else {<a name="line.4506"></a>
-<span class="sourceLineNo">4507</span>      store.add(cells, memstoreAccounting);<a name="line.4507"></a>
-<span class="sourceLineNo">4508</span>    }<a name="line.4508"></a>
-<span class="sourceLineNo">4509</span>  }<a name="line.4509"></a>
-<span class="sourceLineNo">4510</span><a name="line.4510"></a>
-<span class="sourceLineNo">4511</span>  /**<a name="line.4511"></a>
-<span class="sourceLineNo">4512</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4512"></a>
-<span class="sourceLineNo">4513</span>   */<a name="line.4513"></a>
-<span class="sourceLineNo">4514</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4514"></a>
-<span class="sourceLineNo">4515</span>      throws IOException {<a name="line.4515"></a>
-<span class="sourceLineNo">4516</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4516"></a>
-<span class="sourceLineNo">4517</span>    if (store == null) {<a name="line.4517"></a>
-<span class="sourceLineNo">4518</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4518"></a>
-<span class="sourceLineNo">4519</span>      // Unreachable because checkFamily will throw exception<a name="line.4519"></a>
-<span class="sourceLineNo">4520</span>    }<a name="line.4520"></a>
-<span class="sourceLineNo">4521</span>    store.add(cell, memstoreAccounting);<a name="line.4521"></a>
-<span class="sourceLineNo">4522</span>  }<a name="line.4522"></a>
-<span class="sourceLineNo">4523</span><a name="line.4523"></a>
-<span class="sourceLineNo">4524</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4524"></a>
-<span class="sourceLineNo">4525</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4525"></a>
-<span class="sourceLineNo">4526</span>    for (byte[] family : families) {<a name="line.4526"></a>
-<span class="sourceLineNo">4527</span>      checkFamily(family, durability);<a name="line.4527"></a>
-<span class="sourceLineNo">4528</span>    }<a name="line.4528"></a>
-<span class="sourceLineNo">4529</span>  }<a name="line.4529"></a>
-<span class="sourceLineNo">4530</span><a name="line.4530"></a>
-<span class="sourceLineNo">4531</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4531"></a>
-<span class="sourceLineNo">4532</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4532"></a>
-<span class="sourceLineNo">4533</span>    checkFamily(family);<a name="line.4533"></a>
-<span class="sourceLineNo">4534</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4534"></a>
-<span class="sourceLineNo">4535</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4535"></a>
-<span class="sourceLineNo">4536</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4536"></a>
-<span class="sourceLineNo">4537</span>      throw new InvalidMutationDurabilityException(<a name="line.4537"></a>
-<span class="sourceLineNo">4538</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4538"></a>
-<span class="sourceLineNo">4539</span>              + " need replication");<a name="line.4539"></a>
-<span class="sourceLineNo">4540</span>    }<a name="line.4540"></a>
-<span class="sourceLineNo">4541</span>  }<a name="line.4541"></a>
-<span class="sourceLineNo">4542</span><a name="line.4542"></a>
-<span class="sourceLineNo">4543</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4543"></a>
-<span class="sourceLineNo">4544</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4544"></a>
-<span class="sourceLineNo">4545</span>      throw new NoSuchColumnFamilyException(<a name="line.4545"></a>
-<span class="sourceLineNo">4546</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4546"></a>
-<span class="sourceLineNo">4547</span>              + " in table " + this.htableDescriptor);<a name="line.4547"></a>
-<span class="sourceLineNo">4548</span>    }<a name="line.4548"></a>
-<span class="sourceLineNo">4549</span>  }<a name="line.4549"></a>
-<span class="sourceLineNo">4550</span><a name="line.4550"></a>
-<span class="sourceLineNo">4551</span>  /**<a name="line.4551"></a>
-<span class="sourceLineNo">4552</span>   * Check the collection of families for valid timestamps<a name="line.4552"></a>
-<span class="sourceLineNo">4553</span>   * @param familyMap<a name="line.4553"></a>
-<span class="sourceLineNo">4554</span>   * @param now current timestamp<a name="line.4554"></a>
-<span class="sourceLineNo">4555</span>   * @throws FailedSanityCheckException<a name="line.4555"></a>
-<span class="sourceLineNo">4556</span>   */<a name="line.4556"></a>
-<span class="sourceLineNo">4557</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4557"></a>
-<span class="sourceLineNo">4558</span>      throws FailedSanityCheckException {<a name="line.4558"></a>
-<span class="sourceLineNo">4559</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4559"></a>
-<span class="sourceLineNo">4560</span>      return;<a name="line.4560"></a>
-<span class="sourceLineNo">4561</span>    }<a name="line.4561"></a>
-<span class="sourceLineNo">4562</span>    long maxTs = now + timestampSlop;<a name="line.4562"></a>
-<span class="sourceLineNo">4563</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4563"></a>
-<span class="sourceLineNo">4564</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4564"></a>
-<span class="sourceLineNo">4565</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4565"></a>
-<span class="sourceLineNo">4566</span>      assert kvs instanceof RandomAccess;<a name="line.4566"></a>
-<span class="sourceLineNo">4567</span>      int listSize  = kvs.size();<a name="line.4567"></a>
-<span class="sourceLineNo">4568</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4568"></a>
-<span class="sourceLineNo">4569</span>        Cell cell = kvs.get(i);<a name="line.4569"></a>
-<span class="sourceLineNo">4570</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4570"></a>
-<span class="sourceLineNo">4571</span>        long ts = cell.getTimestamp();<a name="line.4571"></a>
-<span class="sourceLineNo">4572</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4572"></a>
-<span class="sourceLineNo">4573</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4573"></a>
-<span class="sourceLineNo">4574</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4574"></a>
-<span class="sourceLineNo">4575</span>        }<a name="line.4575"></a>
-<span class="sourceLineNo">4576</span>      }<a name="line.4576"></a>
-<span class="sourceLineNo">4577</span>    }<a name="line.4577"></a>
-<span class="sourceLineNo">4578</span>  }<a name="line.4578"></a>
-<span class="sourceLineNo">4579</span><a name="line.4579"></a>
-<span class="sourceLineNo">4580</span>  /*<a name="line.4580"></a>
-<span class="sourceLineNo">4581</span>   * @param size<a name="line.4581"></a>
-<span class="sourceLineNo">4582</span>   * @return True if size is over the flush threshold<a name="line.4582"></a>
-<span class="sourceLineNo">4583</span>   */<a name="line.4583"></a>
-<span class="sourceLineNo">4584</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4584"></a>
-<span class="sourceLineNo">4585</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4585"></a>
-<span class="sourceLineNo">4586</span>  }<a name="line.4586"></a>
-<span class="sourceLineNo">4587</span><a name="line.4587"></a>
-<span class="sourceLineNo">4588</span>  /**<a name="line.4588"></a>
-<span class="sourceLineNo">4589</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4589"></a>
-<span class="sourceLineNo">4590</span>   * the recovered edits back up into this region.<a name="line.4590"></a>
-<span class="sourceLineNo">4591</span>   *<a name="line.4591"></a>
-<span class="sourceLineNo">4592</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4592"></a>
-<span class="sourceLineNo">4593</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4593"></a>
-<span class="sourceLineNo">4594</span>   * reflected in the HFiles.)<a name="line.4594"></a>
-<span class="sourceLineNo">4595</span>   *<a name="line.4595"></a>
-<span class="sourceLineNo">4596</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4596"></a>
-<span class="sourceLineNo">4597</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4597"></a>
-<span class="sourceLineNo">4598</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4598"></a>
-<span class="sourceLineNo">4599</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4599"></a>
-<span class="sourceLineNo">4600</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4600"></a>
-<span class="sourceLineNo">4601</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4601"></a>
-<span class="sourceLineNo">4602</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4602"></a>
-<span class="sourceLineNo">4603</span>   * edits.<a name="line.4603"></a>
-<span class="sourceLineNo">4604</span>   *<a name="line.4604"></a>
-<span class="sourceLineNo">4605</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4605"></a>
-<span class="sourceLineNo">4606</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4606"></a>
-<span class="sourceLineNo">4607</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4607"></a>
-<span class="sourceLineNo">4608</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4608"></a>
-<span class="sourceLineNo">4609</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4609"></a>
-<span class="sourceLineNo">4610</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4610"></a>
-<span class="sourceLineNo">4611</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4611"></a>
-<span class="sourceLineNo">4612</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4612"></a>
-<span class="sourceLineNo">4613</span>   * make sense in a this single region context only -- until we online.<a name="line.4613"></a>
-<span class="sourceLineNo">4614</span>   *<a name="line.4614"></a>
-<span class="sourceLineNo">4615</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4615"></a>
-<span class="sourceLineNo">4616</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4616"></a>
-<span class="sourceLineNo">4617</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4617"></a>
-<span class="sourceLineNo">4618</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4618"></a>
-<span class="sourceLineNo">4619</span>   * @throws IOException<a name="line.4619"></a>
-<span class="sourceLineNo">4620</span>   */<a name="line.4620"></a>
-<span class="sourceLineNo">4621</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4621"></a>
-<span class="sourceLineNo">4622</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4622"></a>
-<span class="sourceLineNo">4623</span>      throws IOException {<a name="line.4623"></a>
-<span class="sourceLineNo">4624</span>    long minSeqIdForTheRegion = -1;<a name="line.4624"></a>
-<span class="sourceLineNo">4625</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4625"></a>
-<span class="sourceLineNo">4626</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4626"></a>
-<span class="sourceLineNo">4627</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4627"></a>
-<span class="sourceLineNo">4628</span>      }<a name="line.4628"></a>
-<span class="sourceLineNo">4629</span>    }<a name="line.4629"></a>
-<span class="sourceLineNo">4630</span>    long seqId = minSeqIdForTheRegion;<a name="line.4630"></a>
-<span class="sourceLineNo">4631</span><a name="line.4631"></a>
-<span class="sourceLineNo">4632</span>    FileSystem walFS = getWalFileSystem();<a name="line.4632"></a>
-<span class="sourceLineNo">4633</span>    FileSystem rootFS = getFilesystem();<a name="line.4633"></a>
-<span class="sourceLineNo">4634</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4634"></a>
-<span class="sourceLineNo">4635</span>      getRegionInfo().getEncodedName());<a name="line.4635"></a>
-<span class="sourceLineNo">4636</span>    Path regionWALDir = getWALRegionDir();<a name="line.4636"></a>
-<span class="sourceLineNo">4637</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4637"></a>
-<span class="sourceLineNo">4638</span><a name="line.4638"></a>
-<span class="sourceLineNo">4639</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4639"></a>
-<span class="sourceLineNo">4640</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4640"></a>
-<span class="sourceLineNo">4641</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4641"></a>
-<span class="sourceLineNo">4642</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4642"></a>
-<span class="sourceLineNo">4643</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4643"></a>
-<span class="sourceLineNo">4644</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4644"></a>
-<span class="sourceLineNo">4645</span>    // under the root dir even if walDir is set.<a name="line.4645"></a>
-<span class="sourceLineNo">4646</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4646"></a>
-<span class="sourceLineNo">4647</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4647"></a>
-<span class="sourceLineNo">4648</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4648"></a>
-<span class="sourceLineNo">4649</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4649"></a>
-<span class="sourceLineNo">4650</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4650"></a>
-<span class="sourceLineNo">4651</span>    }<a name="line.4651"></a>
-<span class="sourceLineNo">4652</span><a name="line.4652"></a>
-<span class="sourceLineNo">4653</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4653"></a>
-<span class="sourceLineNo">4654</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4654"></a>
-<span class="sourceLineNo">4655</span>        files, reporter, regionWALDir));<a name="line.4655"></a>
-<span class="sourceLineNo">4656</span><a name="line.4656"></a>
-<span class="sourceLineNo">4657</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4657"></a>
-<span class="sourceLineNo">4658</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4658"></a>
-<span class="sourceLineNo">4659</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4659"></a>
-<span class="sourceLineNo">4660</span>    }<a name="line.4660"></a>
-<span class="sourceLineNo">4661</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4661"></a>
-<span class="sourceLineNo">4662</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4662"></a>
-<span class="sourceLineNo">4663</span>      // For debugging data loss issues!<a name="line.4663"></a>
-<span class="sourceLineNo">4664</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4664"></a>
-<span class="sourceLineNo">4665</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4665"></a>
-<span class="sourceLineNo">4666</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4666"></a>
-<span class="sourceLineNo">4667</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4667"></a>
-<span class="sourceLineNo">4668</span>      for (Path file : files) {<a name="line.4668"></a>
-<span class="sourceLineNo">4669</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4669"></a>
-<span class="sourceLineNo">4670</span>      }<a name="line.4670"></a>
-<span class="sourceLineNo">4671</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4671"></a>
-<span class="sourceLineNo">4672</span>    } else {<a name="line.4672"></a>
-<span class="sourceLineNo">4673</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4673"></a>
-<span class="sourceLineNo">4674</span>        if (!walFS.delete(file, false)) {<a name="line.4674"></a>
-<span class="sourceLineNo">4675</span>          LOG.error("Failed delete of {}", file);<a name="line.4675"></a>
-<span class="sourceLineNo">4676</span>        } else {<a name="line.4676"></a>
-<span class="sourceLineNo">4677</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4677"></a>
-<span class="sourceLineNo">4678</span>        }<a name="line.4678"></a>
-<span class="sourceLineNo">4679</span>      }<a name="line.4679"></a>
-<span class="sourceLineNo">4680</span>      for (Path file : filesUnderRootDir) {<a name="line.4680"></a>
-<span class="sourceLineNo">4681</span>        if (!rootFS.delete(file, false)) {<a name="line.4681"></a>
-<span class="sourceLineNo">4682</span>          LOG.error("Failed delete of {}", file);<a name="line.4682"></a>
-<span class="sourceLineNo">4683</span>        } else {<a name="line.4683"></a>
-<span class="sourceLineNo">4684</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4684"></a>
-<span class="sourceLineNo">4685</span>        }<a name="line.4685"></a>
-<span class="sourceLineNo">4686</span>      }<a name="line.4686"></a>
-<span class="sourceLineNo">4687</span>    }<a name="line.4687"></a>
-<span class="sourceLineNo">4688</span>    return seqId;<a name="line.4688"></a>
-<span class="sourceLineNo">4689</span>  }<a name="line.4689"></a>
-<span class="sourceLineNo">4690</span><a name="line.4690"></a>
-<span class="sourceLineNo">4691</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4691"></a>
-<span class="sourceLineNo">4692</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4692"></a>
-<span class="sourceLineNo">4693</span>      throws IOException {<a name="line.4693"></a>
-<span class="sourceLineNo">4694</span>    long seqid = minSeqIdForTheRegion;<a name="line.4694"></a>
-<span class="sourceLineNo">4695</span>    if (LOG.isDebugEnabled()) {<a name="line.4695"></a>
-<span class="sourceLineNo">4696</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4696"></a>
-<span class="sourceLineNo">4697</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4697"></a>
-<span class="sourceLineNo">4698</span>    }<a name="line.4698"></a>
-<span class="sourceLineNo">4699</span><a name="line.4699"></a>
-<span class="sourceLineNo">4700</span>    if (files == null || files.isEmpty()) {<a name="line.4700"></a>
-<span class="sourceLineNo">4701</span>      return minSeqIdForTheRegion;<a name="line.4701"></a>
-<span class="sourceLineNo">4702</span>    }<a name="line.4702"></a>
-<span class="sourceLineNo">4703</span><a name="line.4703"></a>
-<span class="sourceLineNo">4704</span>    for (Path edits: files) {<a name="line.4704"></a>
-<span class="sourceLineNo">4705</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4705"></a>
-<span class="sourceLineNo">4706</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4706"></a>
-<span class="sourceLineNo">4707</span>        continue;<a name="line.4707"></a>
-<span class="sourceLineNo">4708</span>      }<a name="line.4708"></a>
-<span class="sourceLineNo">4709</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4709"></a>
-<span class="sourceLineNo">4710</span><a name="line.4710"></a>
-<span class="sourceLineNo">4711</span>      long maxSeqId;<a name="line.4711"></a>
-<span class="sourceLineNo">4712</span>      String fileName = edits.getName();<a name="line.4712"></a>
-<span class="sourceLineNo">4713</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4713"></a>
-<span class="sourceLineNo">4714</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4714"></a>
-<span class="sourceLineNo">4715</span>        if (LOG.isDebugEnabled()) {<a name="line.4715"></a>
-<span class="sourceLineNo">4716</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4716"></a>
-<span class="sourceLineNo">4717</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4717"></a>
-<span class="sourceLineNo">4718</span>              + ", skipped the whole file, path=" + edits;<a name="line.4718"></a>
-<span class="sourceLineNo">4719</span>          LOG.debug(msg);<a name="line.4719"></a>
-<span class="sourceLineNo">4720</span>        }<a name="line.4720"></a>
-<span class="sourceLineNo">4721</span>        continue;<a name="line.4721"></a>
-<span class="sourceLineNo">4722</span>      }<a name="line.4722"></a>
-<span class="sourceLineNo">4723</span><a name="line.4723"></a>
-<span class="sourceLineNo">4724</span>      try {<a name="line.4724"></a>
-<span class="sourceLineNo">4725</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4725"></a>
-<span class="sourceLineNo">4726</span>        // if seqId is greater<a name="line.4726"></a>
-<span class="sourceLineNo">4727</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4727"></a>
-<span class="sourceLineNo">4728</span>      } catch (IOException e) {<a name="line.4728"></a>
-<span class="sourceLineNo">4729</span>        boolean skipErrors = conf.getBoolean(<a name="line.4729"></a>
-<span class="sourceLineNo">4730</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4730"></a>
-<span class="sourceLineNo">4731</span>            conf.getBoolean(<a name="line.4731"></a>
-<span class="sourceLineNo">4732</span>                "hbase.skip.errors",<a name="line.4732"></a>
-<span class="sourceLineNo">4733</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4733"></a>
-<span class="sourceLineNo">4734</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4734"></a>
-<span class="sourceLineNo">4735</span>          LOG.warn(<a name="line.4735"></a>
-<span class="sourceLineNo">4736</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4736"></a>
-<span class="sourceLineNo">4737</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4737"></a>
-<span class="sourceLineNo">4738</span>        }<a name="line.4738"></a>
-<span class="sourceLineNo">4739</span>        if (skipErrors) {<a name="line.4739"></a>
-<span class="sourceLineNo">4740</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4740"></a>
-<span class="sourceLineNo">4741</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4741"></a>
-<span class="sourceLineNo">4742</span>              + "=true so continuing. Renamed " + edits +<a name="line.4742"></a>
-<span class="sourceLineNo">4743</span>              " as " + p, e);<a name="line.4743"></a>
-<span class="sourceLineNo">4744</span>        } else {<a name="line.4744"></a>
-<span class="sourceLineNo">4745</span>          throw e;<a name="line.4745"></a>
-<span class="sourceLineNo">4746</span>        }<a name="line.4746"></a>
-<span class="sourceLineNo">4747</span>      }<a name="line.4747"></a>
-<span class="sourceLineNo">4748</span>    }<a name="line.4748"></a>
-<span class="sourceLineNo">4749</span>    return seqid;<a name="line.4749"></a>
-<span class="sourceLineNo">4750</span>  }<a name="line.4750"></a>
-<span class="sourceLineNo">4751</span><a name="line.4751"></a>
-<span class="sourceLineNo">4752</span>  /*<a name="line.4752"></a>
-<span class="sourceLineNo">4753</span>   * @param edits File of recovered edits.<a name="line.4753"></a>
-<span class="sourceLineNo">4754</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4754"></a>
-<span class="sourceLineNo">4755</span>   * must be larger than this to be replayed for each store.<a name="line.4755"></a>
-<span class="sourceLineNo">4756</span>   * @param reporter<a name="line.4756"></a>
-<span class="sourceLineNo">4757</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4757"></a>
-<span class="sourceLineNo">4758</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4758"></a>
-<span class="sourceLineNo">4759</span>   * @throws IOException<a name="line.4759"></a>
-<span class="sourceLineNo">4760</span>   */<a name="line.4760"></a>
-<span class="sourceLineNo">4761</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4761"></a>
-<span class="sourceLineNo">4762</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4762"></a>
-<span class="sourceLineNo">4763</span>    throws IOException {<a name="line.4763"></a>
-<span class="sourceLineNo">4764</span>    String msg = "Replaying edits from " + edits;<a name="line.4764"></a>
-<span class="sourceLineNo">4765</span>    LOG.info(msg);<a name="line.4765"></a>
-<span class="sourceLineNo">4766</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4766"></a>
-<span class="sourceLineNo">4767</span><a name="line.4767"></a>
-<span class="sourceLineNo">4768</span>    status.setStatus("Opening recovered edits");<a name="line.4768"></a>
-<span class="sourceLineNo">4769</span>    WAL.Reader reader = null;<a name="line.4769"></a>
-<span class="sourceLineNo">4770</span>    try {<a name="line.4770"></a>
-<span class="sourceLineNo">4771</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4771"></a>
-<span class="sourceLineNo">4772</span>      long currentEditSeqId = -1;<a name="line.4772"></a>
-<span class="sourceLineNo">4773</span>      long currentReplaySeqId = -1;<a name="line.4773"></a>
-<span class="sourceLineNo">4774</span>      long firstSeqIdInLog = -1;<a name="line.4774"></a>
-<span class="sourceLineNo">4775</span>      long skippedEdits = 0;<a name="line.4775"></a>
-<span class="sourceLineNo">4776</span>      long editsCount = 0;<a name="line.4776"></a>
-<span class="sourceLineNo">4777</span>      long intervalEdits = 0;<a name="line.4777"></a>
-<span class="sourceLineNo">4778</span>      WAL.Entry entry;<a name="line.4778"></a>
-<span class="sourceLineNo">4779</span>      HStore store = null;<a name="line.4779"></a>
-<span class="sourceLineNo">4780</span>      boolean reported_once = false;<a name="line.4780"></a>
-<span class="sourceLineNo">4781</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4781"></a>
-<span class="sourceLineNo">4782</span><a name="line.4782"></a>
-<span class="sourceLineNo">4783</span>      try {<a name="line.4783"></a>
-<span class="sourceLineNo">4784</span>        // How many edits seen before we check elapsed time<a name="line.4784"></a>
-<span class="sourceLineNo">4785</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4785"></a>
-<span class="sourceLineNo">4786</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4786"></a>
-<span class="sourceLineNo">4787</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4787"></a>
-<span class="sourceLineNo">4788</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4788"></a>
-<span class="sourceLineNo">4789</span><a name="line.4789"></a>
-<span class="sourceLineNo">4790</span>        if (coprocessorHost != null) {<a name="line.4790"></a>
-<span class="sourceLineNo">4791</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4791"></a>
-<span class="sourceLineNo">4792</span>        }<a name="line.4792"></a>
-<span class="sourceLineNo">4793</span><a name="line.4793"></a>
-<span class="sourceLineNo">4794</span>        while ((entry = reader.next()) != null) {<a name="line.4794"></a>
-<span class="sourceLineNo">4795</span>          WALKey key = entry.getKey();<a name="line.4795"></a>
-<span class="sourceLineNo">4796</span>          WALEdit val = entry.getEdit();<a name="line.4796"></a>
-<span class="sourceLineNo">4797</span><a name="line.4797"></a>
-<span class="sourceLineNo">4798</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4798"></a>
-<span class="sourceLineNo">4799</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4799"></a>
-<span class="sourceLineNo">4800</span>          }<a name="line.4800"></a>
-<span class="sourceLineNo">4801</span><a name="line.4801"></a>
-<span class="sourceLineNo">4802</span>          if (reporter != null) {<a name="line.4802"></a>
-<span class="sourceLineNo">4803</span>            intervalEdits += val.size();<a name="line.4803"></a>
-<span class="sourceLineNo">4804</span>            if (intervalEdits &gt;= interval) {<a name="line.4804"></a>
-<span class="sourceLineNo">4805</span>              // Number of edits interval reached<a name="line.4805"></a>
-<span class="sourceLineNo">4806</span>              intervalEdits = 0;<a name="line.4806"></a>
-<span class="sourceLineNo">4807</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4807"></a>
-<span class="sourceLineNo">4808</span>              if (lastReport + period &lt;= cur) {<a name="line.4808"></a>
-<span class="sourceLineNo">4809</span>                status.setStatus("Replaying edits..." +<a name="line.4809"></a>
-<span class="sourceLineNo">4810</span>                    " skipped=" + skippedEdits +<a name="line.4810"></a>
-<span class="sourceLineNo">4811</span>                    " edits=" + editsCount);<a name="line.4811"></a>
-<span class="sourceLineNo">4812</span>                // Timeout reached<a name="line.4812"></a>
-<span class="sourceLineNo">4813</span>                if(!reporter.progress()) {<a name="line.4813"></a>
-<span class="sourceLineNo">4814</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4814"></a>
-<span class="sourceLineNo">4815</span>                  LOG.warn(msg);<a name="line.4815"></a>
-<span class="sourceLineNo">4816</span>                  status.abort(msg);<a name="line.4816"></a>
-<span class="sourceLineNo">4817</span>                  throw new IOException(msg);<a name="line.4817"></a>
-<span class="sourceLineNo">4818</span>                }<a name="line.4818"></a>
-<span class="sourceLineNo">4819</span>                reported_once = true;<a name="line.4819"></a>
-<span class="sourceLineNo">4820</span>                lastReport = cur;<a name="line.4820"></a>
-<span class="sourceLineNo">4821</span>              }<a name="line.4821"></a>
-<span class="sourceLineNo">4822</span>            }<a name="line.4822"></a>
-<span class="sourceLineNo">4823</span>          }<a name="line.4823"></a>
-<span class="sourceLineNo">4824</span><a name="line.4824"></a>
-<span class="sourceLineNo">4825</span>          if (firstSeqIdInLog == -1) {<a name="line.4825"></a>
-<span class="sourceLineNo">4826</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4826"></a>
-<span class="sourceLineNo">4827</span>          }<a name="line.4827"></a>
-<span class="sourceLineNo">4828</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4828"></a>
-<span class="sourceLineNo">4829</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4829"></a>
-<span class="sourceLineNo">4830</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4830"></a>
-<span class="sourceLineNo">4831</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4831"></a>
-<span class="sourceLineNo">4832</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4832"></a>
-<span class="sourceLineNo">4833</span>                + "; edit=" + val);<a name="line.4833"></a>
-<span class="sourceLineNo">4834</span>          } else {<a name="line.4834"></a>
-<span class="sourceLineNo">4835</span>            currentEditSeqId = key.getSequenceId();<a name="line.4835"></a>
-<span class="sourceLineNo">4836</span>          }<a name="line.4836"></a>
-<span class="sourceLineNo">4837</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4837"></a>
-<span class="sourceLineNo">4838</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4838"></a>
-<span class="sourceLineNo">4839</span><a name="line.4839"></a>
-<span class="sourceLineNo">4840</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4840"></a>
-<span class="sourceLineNo">4841</span>          // instead of a KeyValue.<a name="line.4841"></a>
-<span class="sourceLineNo">4842</span>          if (coprocessorHost != null) {<a name="line.4842"></a>
-<span class="sourceLineNo">4843</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4843"></a>
-<span class="sourceLineNo">4844</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4844"></a>
-<span class="sourceLineNo">4845</span>              // if bypass this wal entry, ignore it ...<a name="line.4845"></a>
-<span class="sourceLineNo">4846</span>              continue;<a name="line.4846"></a>
-<span class="sourceLineNo">4847</span>            }<a name="line.4847"></a>
-<span class="sourceLineNo">4848</span>          }<a name="line.4848"></a>
-<span class="sourceLineNo">4849</span>          boolean checkRowWithinBoundary = false;<a name="line.4849"></a>
-<span class="sourceLineNo">4850</span>          // Check this edit is for this region.<a name="line.4850"></a>
-<span class="sourceLineNo">4851</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4851"></a>
-<span class="sourceLineNo">4852</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4852"></a>
-<span class="sourceLineNo">4853</span>            checkRowWithinBoundary = true;<a name="line.4853"></a>
-<span class="sourceLineNo">4854</span>          }<a name="line.4854"></a>
-<span class="sourceLineNo">4855</span><a name="line.4855"></a>
-<span class="sourceLineNo">4856</span>          boolean flush = false;<a name="line.4856"></a>
-<span class="sourceLineNo">4857</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4857"></a>
-<span class="sourceLineNo">4858</span>          for (Cell cell: val.getCells()) {<a name="line.4858"></a>
-<span class="sourceLineNo">4859</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4859"></a>
-<span class="sourceLineNo">4860</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4860"></a>
-<span class="sourceLineNo">4861</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4861"></a>
-<span class="sourceLineNo">4862</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4862"></a>
-<span class="sourceLineNo">4863</span>              if (!checkRowWithinBoundary) {<a name="line.4863"></a>
-<span class="sourceLineNo">4864</span>                //this is a special edit, we should handle it<a name="line.4864"></a>
-<span class="sourceLineNo">4865</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4865"></a>
-<span class="sourceLineNo">4866</span>                if (compaction != null) {<a name="line.4866"></a>
-<span class="sourceLineNo">4867</span>                  //replay the compaction<a name="line.4867"></a>
-<span class="sourceLineNo">4868</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4868"></a>
-<span class="sourceLineNo">4869</span>                }<a name="line.4869"></a>
-<span class="sourceLineNo">4870</span>              }<a name="line.4870"></a>
-<span class="sourceLineNo">4871</span>              skippedEdits++;<a name="line.4871"></a>
-<span class="sourceLineNo">4872</span>              continue;<a name="line.4872"></a>
-<span class="sourceLineNo">4873</span>            }<a name="line.4873"></a>
-<span class="sourceLineNo">4874</span>            // Figure which store the edit is meant for.<a name="line.4874"></a>
-<span class="sourceLineNo">4875</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4875"></a>
-<span class="sourceLineNo">4876</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4876"></a>
-<span class="sourceLineNo">4877</span>              store = getStore(cell);<a name="line.4877"></a>
-<span class="sourceLineNo">4878</span>            }<a name="line.4878"></a>
-<span class="sourceLineNo">4879</span>            if (store == null) {<a name="line.4879"></a>
-<span class="sourceLineNo">4880</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4880"></a>
-<span class="sourceLineNo">4881</span>              // crash and redeploy?<a name="line.4881"></a>
-<span class="sourceLineNo">4882</span>              LOG.warn("No family for " + cell);<a name="line.4882"></a>
-<span class="sourceLineNo">4883</span>              skippedEdits++;<a name="line.4883"></a>
-<span class="sourceLineNo">4884</span>              continue;<a name="line.4884"></a>
-<span class="sourceLineNo">4885</span>            }<a name="line.4885"></a>
-<span class="sourceLineNo">4886</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4886"></a>
-<span class="sourceLineNo">4887</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4887"></a>
-<span class="sourceLineNo">4888</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4888"></a>
-<span class="sourceLineNo">4889</span>              skippedEdits++;<a name="line.4889"></a>
-<span class="sourceLineNo">4890</span>              continue;<a name="line.4890"></a>
-<span class="sourceLineNo">4891</span>            }<a name="line.4891"></a>
-<span class="sourceLineNo">4892</span>            // Now, figure if we should skip this edit.<a name="line.4892"></a>
-<span class="sourceLineNo">4893</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4893"></a>
-<span class="sourceLineNo">4894</span>                .getName())) {<a name="line.4894"></a>
-<span class="sourceLineNo">4895</span>              skippedEdits++;<a name="line.4895"></a>
-<span class="sourceLineNo">4896</span>              continue;<a name="line.4896"></a>
-<span class="sourceLineNo">4897</span>            }<a name="line.4897"></a>
-<span class="sourceLineNo">4898</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4898"></a>
-<span class="sourceLineNo">4899</span><a name="line.4899"></a>
-<span class="sourceLineNo">4900</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4900"></a>
-<span class="sourceLineNo">4901</span>            editsCount++;<a name="line.4901"></a>
-<span class="sourceLineNo">4902</span>          }<a name="line.4902"></a>
-<span class="sourceLineNo">4903</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4903"></a>
-<span class="sourceLineNo">4904</span>          incMemStoreSize(mss);<a name="line.4904"></a>
-<span class="sourceLineNo">4905</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4905"></a>
-<span class="sourceLineNo">4906</span>          if (flush) {<a name="line.4906"></a>
-<span class="sourceLineNo">4907</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4907"></a>
-<span class="sourceLineNo">4908</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4908"></a>
-<span class="sourceLineNo">4909</span>          }<a name="line.4909"></a>
-<span class="sourceLineNo">4910</span><a name="line.4910"></a>
-<span class="sourceLineNo">4911</span>          if (coprocessorHost != null) {<a name="line.4911"></a>
-<span class="sourceLineNo">4912</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4912"></a>
-<span class="sourceLineNo">4913</span>          }<a name="line.4913"></a>
-<span class="sourceLineNo">4914</span>        }<a name="line.4914"></a>
-<span class="sourceLineNo">4915</span><a name="line.4915"></a>
-<span class="sourceLineNo">4916</span>        if (coprocessorHost != null) {<a name="line.4916"></a>
-<span class="sourceLineNo">4917</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4917"></a>
-<span class="sourceLineNo">4918</span>        }<a name="line.4918"></a>
-<span class="sourceLineNo">4919</span>      } catch (EOFException eof) {<a name="line.4919"></a>
-<span class="sourceLineNo">4920</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4920"></a>
-<span class="sourceLineNo">4921</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4921"></a>
-<span class="sourceLineNo">4922</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4922"></a>
-<span class="sourceLineNo">4923</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4923"></a>
-<span class="sourceLineNo">4924</span>        LOG.warn(msg, eof);<a name="line.4924"></a>
-<span class="sourceLineNo">4925</span>        status.abort(msg);<a name="line.4925"></a>
-<span class="sourceLineNo">4926</span>      } catch (IOException ioe) {<a name="line.4926"></a>
-<span class="sourceLineNo">4927</span>        // If the IOE resulted from bad file format,<a name="line.4927"></a>
-<span class="sourceLineNo">4928</span>        // then this problem is idempotent and retrying won't help<a name="line.4928"></a>
-<span class="sourceLineNo">4929</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4929"></a>
-<span class="sourceLineNo">4930</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4930"></a>
-<span class="sourceLineNo">4931</span>          msg = "File corruption enLongAddered!  " +<a name="line.4931"></a>
-<span class="sourceLineNo">4932</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4932"></a>
-<span class="sourceLineNo">4933</span>          LOG.warn(msg, ioe);<a name="line.4933"></a>
-<span class="sourceLineNo">4934</span>          status.setStatus(msg);<a name="line.4934"></a>
-<span class="sourceLineNo">4935</span>        } else {<a name="line.4935"></a>
-<span class="sourceLineNo">4936</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4936"></a>
-<span class="sourceLineNo">4937</span>          // other IO errors may be transient (bad network connection,<a name="line.4937"></a>
-<span class="sourceLineNo">4938</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4938"></a>
-<span class="sourceLineNo">4939</span>          throw ioe;<a name="line.4939"></a>
-<span class="sourceLineNo">4940</span>        }<a name="line.4940"></a>
-<span class="sourceLineNo">4941</span>      }<a name="line.4941"></a>
-<span class="sourceLineNo">4942</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4942"></a>
-<span class="sourceLineNo">4943</span>        reporter.progress();<a name="line.4943"></a>
+<span class="sourceLineNo">4334</span>      case GREATER:<a name="line.4334"></a>
+<span class="sourceLineNo">4335</span>        matches = compareResult &gt; 0;<a name="line.4335"></a>
+<span class="sourceLineNo">4336</span>        break;<a name="line.4336"></a>
+<span class="sourceLineNo">4337</span>      default:<a name="line.4337"></a>
+<span class="sourceLineNo">4338</span>        throw new RuntimeException("Unknown Compare op " + op.name());<a name="line.4338"></a>
+<span class="sourceLineNo">4339</span>    }<a name="line.4339"></a>
+<span class="sourceLineNo">4340</span>    return matches;<a name="line.4340"></a>
+<span class="sourceLineNo">4341</span>  }<a name="line.4341"></a>
+<span class="sourceLineNo">4342</span><a name="line.4342"></a>
+<span class="sourceLineNo">4343</span><a name="line.4343"></a>
+<span class="sourceLineNo">4344</span>  private void doBatchMutate(Mutation mutation) throws IOException {<a name="line.4344"></a>
+<span class="sourceLineNo">4345</span>    // Currently this is only called for puts and deletes, so no nonces.<a name="line.4345"></a>
+<span class="sourceLineNo">4346</span>    OperationStatus[] batchMutate = this.batchMutate(new Mutation[]{mutation});<a name="line.4346"></a>
+<span class="sourceLineNo">4347</span>    if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {<a name="line.4347"></a>
+<span class="sourceLineNo">4348</span>      throw new FailedSanityCheckException(batchMutate[0].getExceptionMsg());<a name="line.4348"></a>
+<span class="sourceLineNo">4349</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {<a name="line.4349"></a>
+<span class="sourceLineNo">4350</span>      throw new NoSuchColumnFamilyException(batchMutate[0].getExceptionMsg());<a name="line.4350"></a>
+<span class="sourceLineNo">4351</span>    } else if (batchMutate[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {<a name="line.4351"></a>
+<span class="sourceLineNo">4352</span>      throw new RegionTooBusyException(batchMutate[0].getExceptionMsg());<a name="line.4352"></a>
+<span class="sourceLineNo">4353</span>    }<a name="line.4353"></a>
+<span class="sourceLineNo">4354</span>  }<a name="line.4354"></a>
+<span class="sourceLineNo">4355</span><a name="line.4355"></a>
+<span class="sourceLineNo">4356</span>  /**<a name="line.4356"></a>
+<span class="sourceLineNo">4357</span>   * Complete taking the snapshot on the region. Writes the region info and adds references to the<a name="line.4357"></a>
+<span class="sourceLineNo">4358</span>   * working snapshot directory.<a name="line.4358"></a>
+<span class="sourceLineNo">4359</span>   *<a name="line.4359"></a>
+<span class="sourceLineNo">4360</span>   * TODO for api consistency, consider adding another version with no {@link ForeignExceptionSnare}<a name="line.4360"></a>
+<span class="sourceLineNo">4361</span>   * arg.  (In the future other cancellable HRegion methods could eventually add a<a name="line.4361"></a>
+<span class="sourceLineNo">4362</span>   * {@link ForeignExceptionSnare}, or we could do something fancier).<a name="line.4362"></a>
+<span class="sourceLineNo">4363</span>   *<a name="line.4363"></a>
+<span class="sourceLineNo">4364</span>   * @param desc snapshot description object<a name="line.4364"></a>
+<span class="sourceLineNo">4365</span>   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to<a name="line.4365"></a>
+<span class="sourceLineNo">4366</span>   *   bail out.  This is allowed to be null and will just be ignored in that case.<a name="line.4366"></a>
+<span class="sourceLineNo">4367</span>   * @throws IOException if there is an external or internal error causing the snapshot to fail<a name="line.4367"></a>
+<span class="sourceLineNo">4368</span>   */<a name="line.4368"></a>
+<span class="sourceLineNo">4369</span>  public void addRegionToSnapshot(SnapshotDescription desc,<a name="line.4369"></a>
+<span class="sourceLineNo">4370</span>      ForeignExceptionSnare exnSnare) throws IOException {<a name="line.4370"></a>
+<span class="sourceLineNo">4371</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.4371"></a>
+<span class="sourceLineNo">4372</span>    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);<a name="line.4372"></a>
+<span class="sourceLineNo">4373</span><a name="line.4373"></a>
+<span class="sourceLineNo">4374</span>    SnapshotManifest manifest = SnapshotManifest.create(conf, getFilesystem(),<a name="line.4374"></a>
+<span class="sourceLineNo">4375</span>            snapshotDir, desc, exnSnare);<a name="line.4375"></a>
+<span class="sourceLineNo">4376</span>    manifest.addRegion(this);<a name="line.4376"></a>
+<span class="sourceLineNo">4377</span>  }<a name="line.4377"></a>
+<span class="sourceLineNo">4378</span><a name="line.4378"></a>
+<span class="sourceLineNo">4379</span>  private void updateSequenceId(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final long sequenceId)<a name="line.4379"></a>
+<span class="sourceLineNo">4380</span>      throws IOException {<a name="line.4380"></a>
+<span class="sourceLineNo">4381</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4381"></a>
+<span class="sourceLineNo">4382</span>      if (cells == null) return;<a name="line.4382"></a>
+<span class="sourceLineNo">4383</span>      for (Cell cell : cells) {<a name="line.4383"></a>
+<span class="sourceLineNo">4384</span>        PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.4384"></a>
+<span class="sourceLineNo">4385</span>      }<a name="line.4385"></a>
+<span class="sourceLineNo">4386</span>    }<a name="line.4386"></a>
+<span class="sourceLineNo">4387</span>  }<a name="line.4387"></a>
+<span class="sourceLineNo">4388</span><a name="line.4388"></a>
+<span class="sourceLineNo">4389</span>  /**<a name="line.4389"></a>
+<span class="sourceLineNo">4390</span>   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}<a name="line.4390"></a>
+<span class="sourceLineNo">4391</span>   * provided current timestamp.<a name="line.4391"></a>
+<span class="sourceLineNo">4392</span>   * @param cellItr<a name="line.4392"></a>
+<span class="sourceLineNo">4393</span>   * @param now<a name="line.4393"></a>
+<span class="sourceLineNo">4394</span>   */<a name="line.4394"></a>
+<span class="sourceLineNo">4395</span>  private static void updateCellTimestamps(final Iterable&lt;List&lt;Cell&gt;&gt; cellItr, final byte[] now)<a name="line.4395"></a>
+<span class="sourceLineNo">4396</span>      throws IOException {<a name="line.4396"></a>
+<span class="sourceLineNo">4397</span>    for (List&lt;Cell&gt; cells: cellItr) {<a name="line.4397"></a>
+<span class="sourceLineNo">4398</span>      if (cells == null) continue;<a name="line.4398"></a>
+<span class="sourceLineNo">4399</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4399"></a>
+<span class="sourceLineNo">4400</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4400"></a>
+<span class="sourceLineNo">4401</span>      assert cells instanceof RandomAccess;<a name="line.4401"></a>
+<span class="sourceLineNo">4402</span>      int listSize = cells.size();<a name="line.4402"></a>
+<span class="sourceLineNo">4403</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4403"></a>
+<span class="sourceLineNo">4404</span>        PrivateCellUtil.updateLatestStamp(cells.get(i), now);<a name="line.4404"></a>
+<span class="sourceLineNo">4405</span>      }<a name="line.4405"></a>
+<span class="sourceLineNo">4406</span>    }<a name="line.4406"></a>
+<span class="sourceLineNo">4407</span>  }<a name="line.4407"></a>
+<span class="sourceLineNo">4408</span><a name="line.4408"></a>
+<span class="sourceLineNo">4409</span>  /**<a name="line.4409"></a>
+<span class="sourceLineNo">4410</span>   * Possibly rewrite incoming cell tags.<a name="line.4410"></a>
+<span class="sourceLineNo">4411</span>   */<a name="line.4411"></a>
+<span class="sourceLineNo">4412</span>  void rewriteCellTags(Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, final Mutation m) {<a name="line.4412"></a>
+<span class="sourceLineNo">4413</span>    // Check if we have any work to do and early out otherwise<a name="line.4413"></a>
+<span class="sourceLineNo">4414</span>    // Update these checks as more logic is added here<a name="line.4414"></a>
+<span class="sourceLineNo">4415</span>    if (m.getTTL() == Long.MAX_VALUE) {<a name="line.4415"></a>
+<span class="sourceLineNo">4416</span>      return;<a name="line.4416"></a>
+<span class="sourceLineNo">4417</span>    }<a name="line.4417"></a>
+<span class="sourceLineNo">4418</span><a name="line.4418"></a>
+<span class="sourceLineNo">4419</span>    // From this point we know we have some work to do<a name="line.4419"></a>
+<span class="sourceLineNo">4420</span>    for (Map.Entry&lt;byte[], List&lt;Cell&gt;&gt; e: familyMap.entrySet()) {<a name="line.4420"></a>
+<span class="sourceLineNo">4421</span>      List&lt;Cell&gt; cells = e.getValue();<a name="line.4421"></a>
+<span class="sourceLineNo">4422</span>      assert cells instanceof RandomAccess;<a name="line.4422"></a>
+<span class="sourceLineNo">4423</span>      int listSize = cells.size();<a name="line.4423"></a>
+<span class="sourceLineNo">4424</span>      for (int i = 0; i &lt; listSize; i++) {<a name="line.4424"></a>
+<span class="sourceLineNo">4425</span>        Cell cell = cells.get(i);<a name="line.4425"></a>
+<span class="sourceLineNo">4426</span>        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);<a name="line.4426"></a>
+<span class="sourceLineNo">4427</span>        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());<a name="line.4427"></a>
+<span class="sourceLineNo">4428</span>        // Rewrite the cell with the updated set of tags<a name="line.4428"></a>
+<span class="sourceLineNo">4429</span>        cells.set(i, PrivateCellUtil.createCell(cell, newTags));<a name="line.4429"></a>
+<span class="sourceLineNo">4430</span>      }<a name="line.4430"></a>
+<span class="sourceLineNo">4431</span>    }<a name="line.4431"></a>
+<span class="sourceLineNo">4432</span>  }<a name="line.4432"></a>
+<span class="sourceLineNo">4433</span><a name="line.4433"></a>
+<span class="sourceLineNo">4434</span>  /*<a name="line.4434"></a>
+<span class="sourceLineNo">4435</span>   * Check if resources to support an update.<a name="line.4435"></a>
+<span class="sourceLineNo">4436</span>   *<a name="line.4436"></a>
+<span class="sourceLineNo">4437</span>   * We throw RegionTooBusyException if above memstore limit<a name="line.4437"></a>
+<span class="sourceLineNo">4438</span>   * and expect client to retry using some kind of backoff<a name="line.4438"></a>
+<span class="sourceLineNo">4439</span>  */<a name="line.4439"></a>
+<span class="sourceLineNo">4440</span>  void checkResources() throws RegionTooBusyException {<a name="line.4440"></a>
+<span class="sourceLineNo">4441</span>    // If catalog region, do not impose resource constraints or block updates.<a name="line.4441"></a>
+<span class="sourceLineNo">4442</span>    if (this.getRegionInfo().isMetaRegion()) return;<a name="line.4442"></a>
+<span class="sourceLineNo">4443</span><a name="line.4443"></a>
+<span class="sourceLineNo">4444</span>    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();<a name="line.4444"></a>
+<span class="sourceLineNo">4445</span>    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {<a name="line.4445"></a>
+<span class="sourceLineNo">4446</span>      blockedRequestsCount.increment();<a name="line.4446"></a>
+<span class="sourceLineNo">4447</span>      requestFlush();<a name="line.4447"></a>
+<span class="sourceLineNo">4448</span>      // Don't print current limit because it will vary too much. The message is used as a key<a name="line.4448"></a>
+<span class="sourceLineNo">4449</span>      // over in RetriesExhaustedWithDetailsException processing.<a name="line.4449"></a>
+<span class="sourceLineNo">4450</span>      throw new RegionTooBusyException("Over memstore limit=" +<a name="line.4450"></a>
+<span class="sourceLineNo">4451</span>        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +<a name="line.4451"></a>
+<span class="sourceLineNo">4452</span>        ", regionName=" +<a name="line.4452"></a>
+<span class="sourceLineNo">4453</span>          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +<a name="line.4453"></a>
+<span class="sourceLineNo">4454</span>          ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.4454"></a>
+<span class="sourceLineNo">4455</span>              this.getRegionServerServices().getServerName()));<a name="line.4455"></a>
+<span class="sourceLineNo">4456</span>    }<a name="line.4456"></a>
+<span class="sourceLineNo">4457</span>  }<a name="line.4457"></a>
+<span class="sourceLineNo">4458</span><a name="line.4458"></a>
+<span class="sourceLineNo">4459</span>  /**<a name="line.4459"></a>
+<span class="sourceLineNo">4460</span>   * @throws IOException Throws exception if region is in read-only mode.<a name="line.4460"></a>
+<span class="sourceLineNo">4461</span>   */<a name="line.4461"></a>
+<span class="sourceLineNo">4462</span>  protected void checkReadOnly() throws IOException {<a name="line.4462"></a>
+<span class="sourceLineNo">4463</span>    if (isReadOnly()) {<a name="line.4463"></a>
+<span class="sourceLineNo">4464</span>      throw new DoNotRetryIOException("region is read only");<a name="line.4464"></a>
+<span class="sourceLineNo">4465</span>    }<a name="line.4465"></a>
+<span class="sourceLineNo">4466</span>  }<a name="line.4466"></a>
+<span class="sourceLineNo">4467</span><a name="line.4467"></a>
+<span class="sourceLineNo">4468</span>  protected void checkReadsEnabled() throws IOException {<a name="line.4468"></a>
+<span class="sourceLineNo">4469</span>    if (!this.writestate.readsEnabled) {<a name="line.4469"></a>
+<span class="sourceLineNo">4470</span>      throw new IOException(getRegionInfo().getEncodedName()<a name="line.4470"></a>
+<span class="sourceLineNo">4471</span>        + ": The region's reads are disabled. Cannot serve the request");<a name="line.4471"></a>
+<span class="sourceLineNo">4472</span>    }<a name="line.4472"></a>
+<span class="sourceLineNo">4473</span>  }<a name="line.4473"></a>
+<span class="sourceLineNo">4474</span><a name="line.4474"></a>
+<span class="sourceLineNo">4475</span>  public void setReadsEnabled(boolean readsEnabled) {<a name="line.4475"></a>
+<span class="sourceLineNo">4476</span>   if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {<a name="line.4476"></a>
+<span class="sourceLineNo">4477</span>     LOG.info(getRegionInfo().getEncodedName() + " : Enabling reads for region.");<a name="line.4477"></a>
+<span class="sourceLineNo">4478</span>    }<a name="line.4478"></a>
+<span class="sourceLineNo">4479</span>    this.writestate.setReadsEnabled(readsEnabled);<a name="line.4479"></a>
+<span class="sourceLineNo">4480</span>  }<a name="line.4480"></a>
+<span class="sourceLineNo">4481</span><a name="line.4481"></a>
+<span class="sourceLineNo">4482</span>  /**<a name="line.4482"></a>
+<span class="sourceLineNo">4483</span>   * Add updates first to the wal and then add values to memstore.<a name="line.4483"></a>
+<span class="sourceLineNo">4484</span>   * &lt;p&gt;<a name="line.4484"></a>
+<span class="sourceLineNo">4485</span>   * Warning: Assumption is caller has lock on passed in row.<a name="line.4485"></a>
+<span class="sourceLineNo">4486</span>   * @param edits Cell updates by column<a name="line.4486"></a>
+<span class="sourceLineNo">4487</span>   */<a name="line.4487"></a>
+<span class="sourceLineNo">4488</span>  void put(final byte[] row, byte[] family, List&lt;Cell&gt; edits) throws IOException {<a name="line.4488"></a>
+<span class="sourceLineNo">4489</span>    NavigableMap&lt;byte[], List&lt;Cell&gt;&gt; familyMap;<a name="line.4489"></a>
+<span class="sourceLineNo">4490</span>    familyMap = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.4490"></a>
+<span class="sourceLineNo">4491</span><a name="line.4491"></a>
+<span class="sourceLineNo">4492</span>    familyMap.put(family, edits);<a name="line.4492"></a>
+<span class="sourceLineNo">4493</span>    Put p = new Put(row, HConstants.LATEST_TIMESTAMP, familyMap);<a name="line.4493"></a>
+<span class="sourceLineNo">4494</span>    doBatchMutate(p);<a name="line.4494"></a>
+<span class="sourceLineNo">4495</span>  }<a name="line.4495"></a>
+<span class="sourceLineNo">4496</span><a name="line.4496"></a>
+<span class="sourceLineNo">4497</span>  /**<a name="line.4497"></a>
+<span class="sourceLineNo">4498</span>   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be<a name="line.4498"></a>
+<span class="sourceLineNo">4499</span>   *          set; when set we will run operations that make sense in the increment/append scenario<a name="line.4499"></a>
+<span class="sourceLineNo">4500</span>   *          but that do not make sense otherwise.<a name="line.4500"></a>
+<span class="sourceLineNo">4501</span>   * @see #applyToMemStore(HStore, Cell, MemStoreSizing)<a name="line.4501"></a>
+<span class="sourceLineNo">4502</span>   */<a name="line.4502"></a>
+<span class="sourceLineNo">4503</span>  private void applyToMemStore(HStore store, List&lt;Cell&gt; cells, boolean delta,<a name="line.4503"></a>
+<span class="sourceLineNo">4504</span>      MemStoreSizing memstoreAccounting) throws IOException {<a name="line.4504"></a>
+<span class="sourceLineNo">4505</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4505"></a>
+<span class="sourceLineNo">4506</span>    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;<a name="line.4506"></a>
+<span class="sourceLineNo">4507</span>    if (upsert) {<a name="line.4507"></a>
+<span class="sourceLineNo">4508</span>      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);<a name="line.4508"></a>
+<span class="sourceLineNo">4509</span>    } else {<a name="line.4509"></a>
+<span class="sourceLineNo">4510</span>      store.add(cells, memstoreAccounting);<a name="line.4510"></a>
+<span class="sourceLineNo">4511</span>    }<a name="line.4511"></a>
+<span class="sourceLineNo">4512</span>  }<a name="line.4512"></a>
+<span class="sourceLineNo">4513</span><a name="line.4513"></a>
+<span class="sourceLineNo">4514</span>  /**<a name="line.4514"></a>
+<span class="sourceLineNo">4515</span>   * @see #applyToMemStore(HStore, List, boolean, MemStoreSizing)<a name="line.4515"></a>
+<span class="sourceLineNo">4516</span>   */<a name="line.4516"></a>
+<span class="sourceLineNo">4517</span>  private void applyToMemStore(HStore store, Cell cell, MemStoreSizing memstoreAccounting)<a name="line.4517"></a>
+<span class="sourceLineNo">4518</span>      throws IOException {<a name="line.4518"></a>
+<span class="sourceLineNo">4519</span>    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!<a name="line.4519"></a>
+<span class="sourceLineNo">4520</span>    if (store == null) {<a name="line.4520"></a>
+<span class="sourceLineNo">4521</span>      checkFamily(CellUtil.cloneFamily(cell));<a name="line.4521"></a>
+<span class="sourceLineNo">4522</span>      // Unreachable because checkFamily will throw exception<a name="line.4522"></a>
+<span class="sourceLineNo">4523</span>    }<a name="line.4523"></a>
+<span class="sourceLineNo">4524</span>    store.add(cell, memstoreAccounting);<a name="line.4524"></a>
+<span class="sourceLineNo">4525</span>  }<a name="line.4525"></a>
+<span class="sourceLineNo">4526</span><a name="line.4526"></a>
+<span class="sourceLineNo">4527</span>  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)<a name="line.4527"></a>
+<span class="sourceLineNo">4528</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4528"></a>
+<span class="sourceLineNo">4529</span>    for (byte[] family : families) {<a name="line.4529"></a>
+<span class="sourceLineNo">4530</span>      checkFamily(family, durability);<a name="line.4530"></a>
+<span class="sourceLineNo">4531</span>    }<a name="line.4531"></a>
+<span class="sourceLineNo">4532</span>  }<a name="line.4532"></a>
+<span class="sourceLineNo">4533</span><a name="line.4533"></a>
+<span class="sourceLineNo">4534</span>  private void checkFamily(final byte[] family, Durability durability)<a name="line.4534"></a>
+<span class="sourceLineNo">4535</span>      throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {<a name="line.4535"></a>
+<span class="sourceLineNo">4536</span>    checkFamily(family);<a name="line.4536"></a>
+<span class="sourceLineNo">4537</span>    if (durability.equals(Durability.SKIP_WAL)<a name="line.4537"></a>
+<span class="sourceLineNo">4538</span>        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope()<a name="line.4538"></a>
+<span class="sourceLineNo">4539</span>        != HConstants.REPLICATION_SCOPE_LOCAL) {<a name="line.4539"></a>
+<span class="sourceLineNo">4540</span>      throw new InvalidMutationDurabilityException(<a name="line.4540"></a>
+<span class="sourceLineNo">4541</span>          "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)<a name="line.4541"></a>
+<span class="sourceLineNo">4542</span>              + " need replication");<a name="line.4542"></a>
+<span class="sourceLineNo">4543</span>    }<a name="line.4543"></a>
+<span class="sourceLineNo">4544</span>  }<a name="line.4544"></a>
+<span class="sourceLineNo">4545</span><a name="line.4545"></a>
+<span class="sourceLineNo">4546</span>  void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {<a name="line.4546"></a>
+<span class="sourceLineNo">4547</span>    if (!this.htableDescriptor.hasColumnFamily(family)) {<a name="line.4547"></a>
+<span class="sourceLineNo">4548</span>      throw new NoSuchColumnFamilyException(<a name="line.4548"></a>
+<span class="sourceLineNo">4549</span>          "Column family " + Bytes.toString(family) + " does not exist in region " + this<a name="line.4549"></a>
+<span class="sourceLineNo">4550</span>              + " in table " + this.htableDescriptor);<a name="line.4550"></a>
+<span class="sourceLineNo">4551</span>    }<a name="line.4551"></a>
+<span class="sourceLineNo">4552</span>  }<a name="line.4552"></a>
+<span class="sourceLineNo">4553</span><a name="line.4553"></a>
+<span class="sourceLineNo">4554</span>  /**<a name="line.4554"></a>
+<span class="sourceLineNo">4555</span>   * Check the collection of families for valid timestamps<a name="line.4555"></a>
+<span class="sourceLineNo">4556</span>   * @param familyMap<a name="line.4556"></a>
+<span class="sourceLineNo">4557</span>   * @param now current timestamp<a name="line.4557"></a>
+<span class="sourceLineNo">4558</span>   * @throws FailedSanityCheckException<a name="line.4558"></a>
+<span class="sourceLineNo">4559</span>   */<a name="line.4559"></a>
+<span class="sourceLineNo">4560</span>  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)<a name="line.4560"></a>
+<span class="sourceLineNo">4561</span>      throws FailedSanityCheckException {<a name="line.4561"></a>
+<span class="sourceLineNo">4562</span>    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {<a name="line.4562"></a>
+<span class="sourceLineNo">4563</span>      return;<a name="line.4563"></a>
+<span class="sourceLineNo">4564</span>    }<a name="line.4564"></a>
+<span class="sourceLineNo">4565</span>    long maxTs = now + timestampSlop;<a name="line.4565"></a>
+<span class="sourceLineNo">4566</span>    for (List&lt;Cell&gt; kvs : familyMap.values()) {<a name="line.4566"></a>
+<span class="sourceLineNo">4567</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.4567"></a>
+<span class="sourceLineNo">4568</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.4568"></a>
+<span class="sourceLineNo">4569</span>      assert kvs instanceof RandomAccess;<a name="line.4569"></a>
+<span class="sourceLineNo">4570</span>      int listSize  = kvs.size();<a name="line.4570"></a>
+<span class="sourceLineNo">4571</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.4571"></a>
+<span class="sourceLineNo">4572</span>        Cell cell = kvs.get(i);<a name="line.4572"></a>
+<span class="sourceLineNo">4573</span>        // see if the user-side TS is out of range. latest = server-side<a name="line.4573"></a>
+<span class="sourceLineNo">4574</span>        long ts = cell.getTimestamp();<a name="line.4574"></a>
+<span class="sourceLineNo">4575</span>        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {<a name="line.4575"></a>
+<span class="sourceLineNo">4576</span>          throw new FailedSanityCheckException("Timestamp for KV out of range "<a name="line.4576"></a>
+<span class="sourceLineNo">4577</span>              + cell + " (too.new=" + timestampSlop + ")");<a name="line.4577"></a>
+<span class="sourceLineNo">4578</span>        }<a name="line.4578"></a>
+<span class="sourceLineNo">4579</span>      }<a name="line.4579"></a>
+<span class="sourceLineNo">4580</span>    }<a name="line.4580"></a>
+<span class="sourceLineNo">4581</span>  }<a name="line.4581"></a>
+<span class="sourceLineNo">4582</span><a name="line.4582"></a>
+<span class="sourceLineNo">4583</span>  /*<a name="line.4583"></a>
+<span class="sourceLineNo">4584</span>   * @param size<a name="line.4584"></a>
+<span class="sourceLineNo">4585</span>   * @return True if size is over the flush threshold<a name="line.4585"></a>
+<span class="sourceLineNo">4586</span>   */<a name="line.4586"></a>
+<span class="sourceLineNo">4587</span>  private boolean isFlushSize(MemStoreSize size) {<a name="line.4587"></a>
+<span class="sourceLineNo">4588</span>    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();<a name="line.4588"></a>
+<span class="sourceLineNo">4589</span>  }<a name="line.4589"></a>
+<span class="sourceLineNo">4590</span><a name="line.4590"></a>
+<span class="sourceLineNo">4591</span>  /**<a name="line.4591"></a>
+<span class="sourceLineNo">4592</span>   * Read the edits put under this region by wal splitting process.  Put<a name="line.4592"></a>
+<span class="sourceLineNo">4593</span>   * the recovered edits back up into this region.<a name="line.4593"></a>
+<span class="sourceLineNo">4594</span>   *<a name="line.4594"></a>
+<span class="sourceLineNo">4595</span>   * &lt;p&gt;We can ignore any wal message that has a sequence ID that's equal to or<a name="line.4595"></a>
+<span class="sourceLineNo">4596</span>   * lower than minSeqId.  (Because we know such messages are already<a name="line.4596"></a>
+<span class="sourceLineNo">4597</span>   * reflected in the HFiles.)<a name="line.4597"></a>
+<span class="sourceLineNo">4598</span>   *<a name="line.4598"></a>
+<span class="sourceLineNo">4599</span>   * &lt;p&gt;While this is running we are putting pressure on memory yet we are<a name="line.4599"></a>
+<span class="sourceLineNo">4600</span>   * outside of our usual accounting because we are not yet an onlined region<a name="line.4600"></a>
+<span class="sourceLineNo">4601</span>   * (this stuff is being run as part of Region initialization).  This means<a name="line.4601"></a>
+<span class="sourceLineNo">4602</span>   * that if we're up against global memory limits, we'll not be flagged to flush<a name="line.4602"></a>
+<span class="sourceLineNo">4603</span>   * because we are not online. We can't be flushed by usual mechanisms anyways;<a name="line.4603"></a>
+<span class="sourceLineNo">4604</span>   * we're not yet online so our relative sequenceids are not yet aligned with<a name="line.4604"></a>
+<span class="sourceLineNo">4605</span>   * WAL sequenceids -- not till we come up online, post processing of split<a name="line.4605"></a>
+<span class="sourceLineNo">4606</span>   * edits.<a name="line.4606"></a>
+<span class="sourceLineNo">4607</span>   *<a name="line.4607"></a>
+<span class="sourceLineNo">4608</span>   * &lt;p&gt;But to help relieve memory pressure, at least manage our own heap size<a name="line.4608"></a>
+<span class="sourceLineNo">4609</span>   * flushing if are in excess of per-region limits.  Flushing, though, we have<a name="line.4609"></a>
+<span class="sourceLineNo">4610</span>   * to be careful and avoid using the regionserver/wal sequenceid.  Its running<a name="line.4610"></a>
+<span class="sourceLineNo">4611</span>   * on a different line to whats going on in here in this region context so if we<a name="line.4611"></a>
+<span class="sourceLineNo">4612</span>   * crashed replaying these edits, but in the midst had a flush that used the<a name="line.4612"></a>
+<span class="sourceLineNo">4613</span>   * regionserver wal with a sequenceid in excess of whats going on in here<a name="line.4613"></a>
+<span class="sourceLineNo">4614</span>   * in this region and with its split editlogs, then we could miss edits the<a name="line.4614"></a>
+<span class="sourceLineNo">4615</span>   * next time we go to recover. So, we have to flush inline, using seqids that<a name="line.4615"></a>
+<span class="sourceLineNo">4616</span>   * make sense in a this single region context only -- until we online.<a name="line.4616"></a>
+<span class="sourceLineNo">4617</span>   *<a name="line.4617"></a>
+<span class="sourceLineNo">4618</span>   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of<a name="line.4618"></a>
+<span class="sourceLineNo">4619</span>   * the maxSeqId for the store to be applied, else its skipped.<a name="line.4619"></a>
+<span class="sourceLineNo">4620</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4620"></a>
+<span class="sourceLineNo">4621</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4621"></a>
+<span class="sourceLineNo">4622</span>   * @throws IOException<a name="line.4622"></a>
+<span class="sourceLineNo">4623</span>   */<a name="line.4623"></a>
+<span class="sourceLineNo">4624</span>  protected long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,<a name="line.4624"></a>
+<span class="sourceLineNo">4625</span>      final CancelableProgressable reporter, final MonitoredTask status)<a name="line.4625"></a>
+<span class="sourceLineNo">4626</span>      throws IOException {<a name="line.4626"></a>
+<span class="sourceLineNo">4627</span>    long minSeqIdForTheRegion = -1;<a name="line.4627"></a>
+<span class="sourceLineNo">4628</span>    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {<a name="line.4628"></a>
+<span class="sourceLineNo">4629</span>      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {<a name="line.4629"></a>
+<span class="sourceLineNo">4630</span>        minSeqIdForTheRegion = maxSeqIdInStore;<a name="line.4630"></a>
+<span class="sourceLineNo">4631</span>      }<a name="line.4631"></a>
+<span class="sourceLineNo">4632</span>    }<a name="line.4632"></a>
+<span class="sourceLineNo">4633</span>    long seqId = minSeqIdForTheRegion;<a name="line.4633"></a>
+<span class="sourceLineNo">4634</span><a name="line.4634"></a>
+<span class="sourceLineNo">4635</span>    FileSystem walFS = getWalFileSystem();<a name="line.4635"></a>
+<span class="sourceLineNo">4636</span>    FileSystem rootFS = getFilesystem();<a name="line.4636"></a>
+<span class="sourceLineNo">4637</span>    Path wrongRegionWALDir = FSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),<a name="line.4637"></a>
+<span class="sourceLineNo">4638</span>      getRegionInfo().getEncodedName());<a name="line.4638"></a>
+<span class="sourceLineNo">4639</span>    Path regionWALDir = getWALRegionDir();<a name="line.4639"></a>
+<span class="sourceLineNo">4640</span>    Path regionDir = FSUtils.getRegionDirFromRootDir(FSUtils.getRootDir(conf), getRegionInfo());<a name="line.4640"></a>
+<span class="sourceLineNo">4641</span><a name="line.4641"></a>
+<span class="sourceLineNo">4642</span>    // We made a mistake in HBASE-20734 so we need to do this dirty hack...<a name="line.4642"></a>
+<span class="sourceLineNo">4643</span>    NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =<a name="line.4643"></a>
+<span class="sourceLineNo">4644</span>      WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);<a name="line.4644"></a>
+<span class="sourceLineNo">4645</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4645"></a>
+<span class="sourceLineNo">4646</span>      filesUnderWrongRegionWALDir, reporter, regionDir));<a name="line.4646"></a>
+<span class="sourceLineNo">4647</span>    // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear<a name="line.4647"></a>
+<span class="sourceLineNo">4648</span>    // under the root dir even if walDir is set.<a name="line.4648"></a>
+<span class="sourceLineNo">4649</span>    NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();<a name="line.4649"></a>
+<span class="sourceLineNo">4650</span>    if (!regionWALDir.equals(regionDir)) {<a name="line.4650"></a>
+<span class="sourceLineNo">4651</span>      filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);<a name="line.4651"></a>
+<span class="sourceLineNo">4652</span>      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,<a name="line.4652"></a>
+<span class="sourceLineNo">4653</span>        filesUnderRootDir, reporter, regionDir));<a name="line.4653"></a>
+<span class="sourceLineNo">4654</span>    }<a name="line.4654"></a>
+<span class="sourceLineNo">4655</span><a name="line.4655"></a>
+<span class="sourceLineNo">4656</span>    NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);<a name="line.4656"></a>
+<span class="sourceLineNo">4657</span>    seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,<a name="line.4657"></a>
+<span class="sourceLineNo">4658</span>        files, reporter, regionWALDir));<a name="line.4658"></a>
+<span class="sourceLineNo">4659</span><a name="line.4659"></a>
+<span class="sourceLineNo">4660</span>    if (seqId &gt; minSeqIdForTheRegion) {<a name="line.4660"></a>
+<span class="sourceLineNo">4661</span>      // Then we added some edits to memory. Flush and cleanup split edit files.<a name="line.4661"></a>
+<span class="sourceLineNo">4662</span>      internalFlushcache(null, seqId, stores.values(), status, false, FlushLifeCycleTracker.DUMMY);<a name="line.4662"></a>
+<span class="sourceLineNo">4663</span>    }<a name="line.4663"></a>
+<span class="sourceLineNo">4664</span>    // Now delete the content of recovered edits. We're done w/ them.<a name="line.4664"></a>
+<span class="sourceLineNo">4665</span>    if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {<a name="line.4665"></a>
+<span class="sourceLineNo">4666</span>      // For debugging data loss issues!<a name="line.4666"></a>
+<span class="sourceLineNo">4667</span>      // If this flag is set, make use of the hfile archiving by making recovered.edits a fake<a name="line.4667"></a>
+<span class="sourceLineNo">4668</span>      // column family. Have to fake out file type too by casting our recovered.edits as storefiles<a name="line.4668"></a>
+<span class="sourceLineNo">4669</span>      String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();<a name="line.4669"></a>
+<span class="sourceLineNo">4670</span>      Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());<a name="line.4670"></a>
+<span class="sourceLineNo">4671</span>      for (Path file : files) {<a name="line.4671"></a>
+<span class="sourceLineNo">4672</span>        fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true));<a name="line.4672"></a>
+<span class="sourceLineNo">4673</span>      }<a name="line.4673"></a>
+<span class="sourceLineNo">4674</span>      getRegionWALFileSystem().removeStoreFiles(fakeFamilyName, fakeStoreFiles);<a name="line.4674"></a>
+<span class="sourceLineNo">4675</span>    } else {<a name="line.4675"></a>
+<span class="sourceLineNo">4676</span>      for (Path file : Iterables.concat(files, filesUnderWrongRegionWALDir)) {<a name="line.4676"></a>
+<span class="sourceLineNo">4677</span>        if (!walFS.delete(file, false)) {<a name="line.4677"></a>
+<span class="sourceLineNo">4678</span>          LOG.error("Failed delete of {}", file);<a name="line.4678"></a>
+<span class="sourceLineNo">4679</span>        } else {<a name="line.4679"></a>
+<span class="sourceLineNo">4680</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4680"></a>
+<span class="sourceLineNo">4681</span>        }<a name="line.4681"></a>
+<span class="sourceLineNo">4682</span>      }<a name="line.4682"></a>
+<span class="sourceLineNo">4683</span>      for (Path file : filesUnderRootDir) {<a name="line.4683"></a>
+<span class="sourceLineNo">4684</span>        if (!rootFS.delete(file, false)) {<a name="line.4684"></a>
+<span class="sourceLineNo">4685</span>          LOG.error("Failed delete of {}", file);<a name="line.4685"></a>
+<span class="sourceLineNo">4686</span>        } else {<a name="line.4686"></a>
+<span class="sourceLineNo">4687</span>          LOG.debug("Deleted recovered.edits file={}", file);<a name="line.4687"></a>
+<span class="sourceLineNo">4688</span>        }<a name="line.4688"></a>
+<span class="sourceLineNo">4689</span>      }<a name="line.4689"></a>
+<span class="sourceLineNo">4690</span>    }<a name="line.4690"></a>
+<span class="sourceLineNo">4691</span>    return seqId;<a name="line.4691"></a>
+<span class="sourceLineNo">4692</span>  }<a name="line.4692"></a>
+<span class="sourceLineNo">4693</span><a name="line.4693"></a>
+<span class="sourceLineNo">4694</span>  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,<a name="line.4694"></a>
+<span class="sourceLineNo">4695</span>      final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)<a name="line.4695"></a>
+<span class="sourceLineNo">4696</span>      throws IOException {<a name="line.4696"></a>
+<span class="sourceLineNo">4697</span>    long seqid = minSeqIdForTheRegion;<a name="line.4697"></a>
+<span class="sourceLineNo">4698</span>    if (LOG.isDebugEnabled()) {<a name="line.4698"></a>
+<span class="sourceLineNo">4699</span>      LOG.debug("Found " + (files == null ? 0 : files.size())<a name="line.4699"></a>
+<span class="sourceLineNo">4700</span>          + " recovered edits file(s) under " + regionDir);<a name="line.4700"></a>
+<span class="sourceLineNo">4701</span>    }<a name="line.4701"></a>
+<span class="sourceLineNo">4702</span><a name="line.4702"></a>
+<span class="sourceLineNo">4703</span>    if (files == null || files.isEmpty()) {<a name="line.4703"></a>
+<span class="sourceLineNo">4704</span>      return minSeqIdForTheRegion;<a name="line.4704"></a>
+<span class="sourceLineNo">4705</span>    }<a name="line.4705"></a>
+<span class="sourceLineNo">4706</span><a name="line.4706"></a>
+<span class="sourceLineNo">4707</span>    for (Path edits: files) {<a name="line.4707"></a>
+<span class="sourceLineNo">4708</span>      if (edits == null || !fs.exists(edits)) {<a name="line.4708"></a>
+<span class="sourceLineNo">4709</span>        LOG.warn("Null or non-existent edits file: " + edits);<a name="line.4709"></a>
+<span class="sourceLineNo">4710</span>        continue;<a name="line.4710"></a>
+<span class="sourceLineNo">4711</span>      }<a name="line.4711"></a>
+<span class="sourceLineNo">4712</span>      if (isZeroLengthThenDelete(fs, edits)) continue;<a name="line.4712"></a>
+<span class="sourceLineNo">4713</span><a name="line.4713"></a>
+<span class="sourceLineNo">4714</span>      long maxSeqId;<a name="line.4714"></a>
+<span class="sourceLineNo">4715</span>      String fileName = edits.getName();<a name="line.4715"></a>
+<span class="sourceLineNo">4716</span>      maxSeqId = Math.abs(Long.parseLong(fileName));<a name="line.4716"></a>
+<span class="sourceLineNo">4717</span>      if (maxSeqId &lt;= minSeqIdForTheRegion) {<a name="line.4717"></a>
+<span class="sourceLineNo">4718</span>        if (LOG.isDebugEnabled()) {<a name="line.4718"></a>
+<span class="sourceLineNo">4719</span>          String msg = "Maximum sequenceid for this wal is " + maxSeqId<a name="line.4719"></a>
+<span class="sourceLineNo">4720</span>              + " and minimum sequenceid for the region is " + minSeqIdForTheRegion<a name="line.4720"></a>
+<span class="sourceLineNo">4721</span>              + ", skipped the whole file, path=" + edits;<a name="line.4721"></a>
+<span class="sourceLineNo">4722</span>          LOG.debug(msg);<a name="line.4722"></a>
+<span class="sourceLineNo">4723</span>        }<a name="line.4723"></a>
+<span class="sourceLineNo">4724</span>        continue;<a name="line.4724"></a>
+<span class="sourceLineNo">4725</span>      }<a name="line.4725"></a>
+<span class="sourceLineNo">4726</span><a name="line.4726"></a>
+<span class="sourceLineNo">4727</span>      try {<a name="line.4727"></a>
+<span class="sourceLineNo">4728</span>        // replay the edits. Replay can return -1 if everything is skipped, only update<a name="line.4728"></a>
+<span class="sourceLineNo">4729</span>        // if seqId is greater<a name="line.4729"></a>
+<span class="sourceLineNo">4730</span>        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));<a name="line.4730"></a>
+<span class="sourceLineNo">4731</span>      } catch (IOException e) {<a name="line.4731"></a>
+<span class="sourceLineNo">4732</span>        boolean skipErrors = conf.getBoolean(<a name="line.4732"></a>
+<span class="sourceLineNo">4733</span>            HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,<a name="line.4733"></a>
+<span class="sourceLineNo">4734</span>            conf.getBoolean(<a name="line.4734"></a>
+<span class="sourceLineNo">4735</span>                "hbase.skip.errors",<a name="line.4735"></a>
+<span class="sourceLineNo">4736</span>                HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));<a name="line.4736"></a>
+<span class="sourceLineNo">4737</span>        if (conf.get("hbase.skip.errors") != null) {<a name="line.4737"></a>
+<span class="sourceLineNo">4738</span>          LOG.warn(<a name="line.4738"></a>
+<span class="sourceLineNo">4739</span>              "The property 'hbase.skip.errors' has been deprecated. Please use " +<a name="line.4739"></a>
+<span class="sourceLineNo">4740</span>                  HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");<a name="line.4740"></a>
+<span class="sourceLineNo">4741</span>        }<a name="line.4741"></a>
+<span class="sourceLineNo">4742</span>        if (skipErrors) {<a name="line.4742"></a>
+<span class="sourceLineNo">4743</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);<a name="line.4743"></a>
+<span class="sourceLineNo">4744</span>          LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS<a name="line.4744"></a>
+<span class="sourceLineNo">4745</span>              + "=true so continuing. Renamed " + edits +<a name="line.4745"></a>
+<span class="sourceLineNo">4746</span>              " as " + p, e);<a name="line.4746"></a>
+<span class="sourceLineNo">4747</span>        } else {<a name="line.4747"></a>
+<span class="sourceLineNo">4748</span>          throw e;<a name="line.4748"></a>
+<span class="sourceLineNo">4749</span>        }<a name="line.4749"></a>
+<span class="sourceLineNo">4750</span>      }<a name="line.4750"></a>
+<span class="sourceLineNo">4751</span>    }<a name="line.4751"></a>
+<span class="sourceLineNo">4752</span>    return seqid;<a name="line.4752"></a>
+<span class="sourceLineNo">4753</span>  }<a name="line.4753"></a>
+<span class="sourceLineNo">4754</span><a name="line.4754"></a>
+<span class="sourceLineNo">4755</span>  /*<a name="line.4755"></a>
+<span class="sourceLineNo">4756</span>   * @param edits File of recovered edits.<a name="line.4756"></a>
+<span class="sourceLineNo">4757</span>   * @param maxSeqIdInStores Maximum sequenceid found in each store.  Edits in wal<a name="line.4757"></a>
+<span class="sourceLineNo">4758</span>   * must be larger than this to be replayed for each store.<a name="line.4758"></a>
+<span class="sourceLineNo">4759</span>   * @param reporter<a name="line.4759"></a>
+<span class="sourceLineNo">4760</span>   * @return the sequence id of the last edit added to this region out of the<a name="line.4760"></a>
+<span class="sourceLineNo">4761</span>   * recovered edits log or &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.<a name="line.4761"></a>
+<span class="sourceLineNo">4762</span>   * @throws IOException<a name="line.4762"></a>
+<span class="sourceLineNo">4763</span>   */<a name="line.4763"></a>
+<span class="sourceLineNo">4764</span>  private long replayRecoveredEdits(final Path edits,<a name="line.4764"></a>
+<span class="sourceLineNo">4765</span>      Map&lt;byte[], Long&gt; maxSeqIdInStores, final CancelableProgressable reporter, FileSystem fs)<a name="line.4765"></a>
+<span class="sourceLineNo">4766</span>    throws IOException {<a name="line.4766"></a>
+<span class="sourceLineNo">4767</span>    String msg = "Replaying edits from " + edits;<a name="line.4767"></a>
+<span class="sourceLineNo">4768</span>    LOG.info(msg);<a name="line.4768"></a>
+<span class="sourceLineNo">4769</span>    MonitoredTask status = TaskMonitor.get().createStatus(msg);<a name="line.4769"></a>
+<span class="sourceLineNo">4770</span><a name="line.4770"></a>
+<span class="sourceLineNo">4771</span>    status.setStatus("Opening recovered edits");<a name="line.4771"></a>
+<span class="sourceLineNo">4772</span>    WAL.Reader reader = null;<a name="line.4772"></a>
+<span class="sourceLineNo">4773</span>    try {<a name="line.4773"></a>
+<span class="sourceLineNo">4774</span>      reader = WALFactory.createReader(fs, edits, conf);<a name="line.4774"></a>
+<span class="sourceLineNo">4775</span>      long currentEditSeqId = -1;<a name="line.4775"></a>
+<span class="sourceLineNo">4776</span>      long currentReplaySeqId = -1;<a name="line.4776"></a>
+<span class="sourceLineNo">4777</span>      long firstSeqIdInLog = -1;<a name="line.4777"></a>
+<span class="sourceLineNo">4778</span>      long skippedEdits = 0;<a name="line.4778"></a>
+<span class="sourceLineNo">4779</span>      long editsCount = 0;<a name="line.4779"></a>
+<span class="sourceLineNo">4780</span>      long intervalEdits = 0;<a name="line.4780"></a>
+<span class="sourceLineNo">4781</span>      WAL.Entry entry;<a name="line.4781"></a>
+<span class="sourceLineNo">4782</span>      HStore store = null;<a name="line.4782"></a>
+<span class="sourceLineNo">4783</span>      boolean reported_once = false;<a name="line.4783"></a>
+<span class="sourceLineNo">4784</span>      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();<a name="line.4784"></a>
+<span class="sourceLineNo">4785</span><a name="line.4785"></a>
+<span class="sourceLineNo">4786</span>      try {<a name="line.4786"></a>
+<span class="sourceLineNo">4787</span>        // How many edits seen before we check elapsed time<a name="line.4787"></a>
+<span class="sourceLineNo">4788</span>        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);<a name="line.4788"></a>
+<span class="sourceLineNo">4789</span>        // How often to send a progress report (default 1/2 master timeout)<a name="line.4789"></a>
+<span class="sourceLineNo">4790</span>        int period = this.conf.getInt("hbase.hstore.report.period", 300000);<a name="line.4790"></a>
+<span class="sourceLineNo">4791</span>        long lastReport = EnvironmentEdgeManager.currentTime();<a name="line.4791"></a>
+<span class="sourceLineNo">4792</span><a name="line.4792"></a>
+<span class="sourceLineNo">4793</span>        if (coprocessorHost != null) {<a name="line.4793"></a>
+<span class="sourceLineNo">4794</span>          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);<a name="line.4794"></a>
+<span class="sourceLineNo">4795</span>        }<a name="line.4795"></a>
+<span class="sourceLineNo">4796</span><a name="line.4796"></a>
+<span class="sourceLineNo">4797</span>        while ((entry = reader.next()) != null) {<a name="line.4797"></a>
+<span class="sourceLineNo">4798</span>          WALKey key = entry.getKey();<a name="line.4798"></a>
+<span class="sourceLineNo">4799</span>          WALEdit val = entry.getEdit();<a name="line.4799"></a>
+<span class="sourceLineNo">4800</span><a name="line.4800"></a>
+<span class="sourceLineNo">4801</span>          if (ng != null) { // some test, or nonces disabled<a name="line.4801"></a>
+<span class="sourceLineNo">4802</span>            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());<a name="line.4802"></a>
+<span class="sourceLineNo">4803</span>          }<a name="line.4803"></a>
+<span class="sourceLineNo">4804</span><a name="line.4804"></a>
+<span class="sourceLineNo">4805</span>          if (reporter != null) {<a name="line.4805"></a>
+<span class="sourceLineNo">4806</span>            intervalEdits += val.size();<a name="line.4806"></a>
+<span class="sourceLineNo">4807</span>            if (intervalEdits &gt;= interval) {<a name="line.4807"></a>
+<span class="sourceLineNo">4808</span>              // Number of edits interval reached<a name="line.4808"></a>
+<span class="sourceLineNo">4809</span>              intervalEdits = 0;<a name="line.4809"></a>
+<span class="sourceLineNo">4810</span>              long cur = EnvironmentEdgeManager.currentTime();<a name="line.4810"></a>
+<span class="sourceLineNo">4811</span>              if (lastReport + period &lt;= cur) {<a name="line.4811"></a>
+<span class="sourceLineNo">4812</span>                status.setStatus("Replaying edits..." +<a name="line.4812"></a>
+<span class="sourceLineNo">4813</span>                    " skipped=" + skippedEdits +<a name="line.4813"></a>
+<span class="sourceLineNo">4814</span>                    " edits=" + editsCount);<a name="line.4814"></a>
+<span class="sourceLineNo">4815</span>                // Timeout reached<a name="line.4815"></a>
+<span class="sourceLineNo">4816</span>                if(!reporter.progress()) {<a name="line.4816"></a>
+<span class="sourceLineNo">4817</span>                  msg = "Progressable reporter failed, stopping replay";<a name="line.4817"></a>
+<span class="sourceLineNo">4818</span>                  LOG.warn(msg);<a name="line.4818"></a>
+<span class="sourceLineNo">4819</span>                  status.abort(msg);<a name="line.4819"></a>
+<span class="sourceLineNo">4820</span>                  throw new IOException(msg);<a name="line.4820"></a>
+<span class="sourceLineNo">4821</span>                }<a name="line.4821"></a>
+<span class="sourceLineNo">4822</span>                reported_once = true;<a name="line.4822"></a>
+<span class="sourceLineNo">4823</span>                lastReport = cur;<a name="line.4823"></a>
+<span class="sourceLineNo">4824</span>              }<a name="line.4824"></a>
+<span class="sourceLineNo">4825</span>            }<a name="line.4825"></a>
+<span class="sourceLineNo">4826</span>          }<a name="line.4826"></a>
+<span class="sourceLineNo">4827</span><a name="line.4827"></a>
+<span class="sourceLineNo">4828</span>          if (firstSeqIdInLog == -1) {<a name="line.4828"></a>
+<span class="sourceLineNo">4829</span>            firstSeqIdInLog = key.getSequenceId();<a name="line.4829"></a>
+<span class="sourceLineNo">4830</span>          }<a name="line.4830"></a>
+<span class="sourceLineNo">4831</span>          if (currentEditSeqId &gt; key.getSequenceId()) {<a name="line.4831"></a>
+<span class="sourceLineNo">4832</span>            // when this condition is true, it means we have a serious defect because we need to<a name="line.4832"></a>
+<span class="sourceLineNo">4833</span>            // maintain increasing SeqId for WAL edits per region<a name="line.4833"></a>
+<span class="sourceLineNo">4834</span>            LOG.error(getRegionInfo().getEncodedName() + " : "<a name="line.4834"></a>
+<span class="sourceLineNo">4835</span>                 + "Found decreasing SeqId. PreId=" + currentEditSeqId + " key=" + key<a name="line.4835"></a>
+<span class="sourceLineNo">4836</span>                + "; edit=" + val);<a name="line.4836"></a>
+<span class="sourceLineNo">4837</span>          } else {<a name="line.4837"></a>
+<span class="sourceLineNo">4838</span>            currentEditSeqId = key.getSequenceId();<a name="line.4838"></a>
+<span class="sourceLineNo">4839</span>          }<a name="line.4839"></a>
+<span class="sourceLineNo">4840</span>          currentReplaySeqId = (key.getOrigLogSeqNum() &gt; 0) ?<a name="line.4840"></a>
+<span class="sourceLineNo">4841</span>            key.getOrigLogSeqNum() : currentEditSeqId;<a name="line.4841"></a>
+<span class="sourceLineNo">4842</span><a name="line.4842"></a>
+<span class="sourceLineNo">4843</span>          // Start coprocessor replay here. The coprocessor is for each WALEdit<a name="line.4843"></a>
+<span class="sourceLineNo">4844</span>          // instead of a KeyValue.<a name="line.4844"></a>
+<span class="sourceLineNo">4845</span>          if (coprocessorHost != null) {<a name="line.4845"></a>
+<span class="sourceLineNo">4846</span>            status.setStatus("Running pre-WAL-restore hook in coprocessors");<a name="line.4846"></a>
+<span class="sourceLineNo">4847</span>            if (coprocessorHost.preWALRestore(this.getRegionInfo(), key, val)) {<a name="line.4847"></a>
+<span class="sourceLineNo">4848</span>              // if bypass this wal entry, ignore it ...<a name="line.4848"></a>
+<span class="sourceLineNo">4849</span>              continue;<a name="line.4849"></a>
+<span class="sourceLineNo">4850</span>            }<a name="line.4850"></a>
+<span class="sourceLineNo">4851</span>          }<a name="line.4851"></a>
+<span class="sourceLineNo">4852</span>          boolean checkRowWithinBoundary = false;<a name="line.4852"></a>
+<span class="sourceLineNo">4853</span>          // Check this edit is for this region.<a name="line.4853"></a>
+<span class="sourceLineNo">4854</span>          if (!Bytes.equals(key.getEncodedRegionName(),<a name="line.4854"></a>
+<span class="sourceLineNo">4855</span>              this.getRegionInfo().getEncodedNameAsBytes())) {<a name="line.4855"></a>
+<span class="sourceLineNo">4856</span>            checkRowWithinBoundary = true;<a name="line.4856"></a>
+<span class="sourceLineNo">4857</span>          }<a name="line.4857"></a>
+<span class="sourceLineNo">4858</span><a name="line.4858"></a>
+<span class="sourceLineNo">4859</span>          boolean flush = false;<a name="line.4859"></a>
+<span class="sourceLineNo">4860</span>          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();<a name="line.4860"></a>
+<span class="sourceLineNo">4861</span>          for (Cell cell: val.getCells()) {<a name="line.4861"></a>
+<span class="sourceLineNo">4862</span>            // Check this edit is for me. Also, guard against writing the special<a name="line.4862"></a>
+<span class="sourceLineNo">4863</span>            // METACOLUMN info such as HBASE::CACHEFLUSH entries<a name="line.4863"></a>
+<span class="sourceLineNo">4864</span>            if (CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {<a name="line.4864"></a>
+<span class="sourceLineNo">4865</span>              // if region names don't match, skipp replaying compaction marker<a name="line.4865"></a>
+<span class="sourceLineNo">4866</span>              if (!checkRowWithinBoundary) {<a name="line.4866"></a>
+<span class="sourceLineNo">4867</span>                //this is a special edit, we should handle it<a name="line.4867"></a>
+<span class="sourceLineNo">4868</span>                CompactionDescriptor compaction = WALEdit.getCompaction(cell);<a name="line.4868"></a>
+<span class="sourceLineNo">4869</span>                if (compaction != null) {<a name="line.4869"></a>
+<span class="sourceLineNo">4870</span>                  //replay the compaction<a name="line.4870"></a>
+<span class="sourceLineNo">4871</span>                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);<a name="line.4871"></a>
+<span class="sourceLineNo">4872</span>                }<a name="line.4872"></a>
+<span class="sourceLineNo">4873</span>              }<a name="line.4873"></a>
+<span class="sourceLineNo">4874</span>              skippedEdits++;<a name="line.4874"></a>
+<span class="sourceLineNo">4875</span>              continue;<a name="line.4875"></a>
+<span class="sourceLineNo">4876</span>            }<a name="line.4876"></a>
+<span class="sourceLineNo">4877</span>            // Figure which store the edit is meant for.<a name="line.4877"></a>
+<span class="sourceLineNo">4878</span>            if (store == null || !CellUtil.matchingFamily(cell,<a name="line.4878"></a>
+<span class="sourceLineNo">4879</span>                store.getColumnFamilyDescriptor().getName())) {<a name="line.4879"></a>
+<span class="sourceLineNo">4880</span>              store = getStore(cell);<a name="line.4880"></a>
+<span class="sourceLineNo">4881</span>            }<a name="line.4881"></a>
+<span class="sourceLineNo">4882</span>            if (store == null) {<a name="line.4882"></a>
+<span class="sourceLineNo">4883</span>              // This should never happen.  Perhaps schema was changed between<a name="line.4883"></a>
+<span class="sourceLineNo">4884</span>              // crash and redeploy?<a name="line.4884"></a>
+<span class="sourceLineNo">4885</span>              LOG.warn("No family for " + cell);<a name="line.4885"></a>
+<span class="sourceLineNo">4886</span>              skippedEdits++;<a name="line.4886"></a>
+<span class="sourceLineNo">4887</span>              continue;<a name="line.4887"></a>
+<span class="sourceLineNo">4888</span>            }<a name="line.4888"></a>
+<span class="sourceLineNo">4889</span>            if (checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(),<a name="line.4889"></a>
+<span class="sourceLineNo">4890</span>              cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())) {<a name="line.4890"></a>
+<span class="sourceLineNo">4891</span>              LOG.warn("Row of " + cell + " is not within region boundary");<a name="line.4891"></a>
+<span class="sourceLineNo">4892</span>              skippedEdits++;<a name="line.4892"></a>
+<span class="sourceLineNo">4893</span>              continue;<a name="line.4893"></a>
+<span class="sourceLineNo">4894</span>            }<a name="line.4894"></a>
+<span class="sourceLineNo">4895</span>            // Now, figure if we should skip this edit.<a name="line.4895"></a>
+<span class="sourceLineNo">4896</span>            if (key.getSequenceId() &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor()<a name="line.4896"></a>
+<span class="sourceLineNo">4897</span>                .getName())) {<a name="line.4897"></a>
+<span class="sourceLineNo">4898</span>              skippedEdits++;<a name="line.4898"></a>
+<span class="sourceLineNo">4899</span>              continue;<a name="line.4899"></a>
+<span class="sourceLineNo">4900</span>            }<a name="line.4900"></a>
+<span class="sourceLineNo">4901</span>            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);<a name="line.4901"></a>
+<span class="sourceLineNo">4902</span><a name="line.4902"></a>
+<span class="sourceLineNo">4903</span>            restoreEdit(store, cell, memStoreSizing);<a name="line.4903"></a>
+<span class="sourceLineNo">4904</span>            editsCount++;<a name="line.4904"></a>
+<span class="sourceLineNo">4905</span>          }<a name="line.4905"></a>
+<span class="sourceLineNo">4906</span>          MemStoreSize mss = memStoreSizing.getMemStoreSize();<a name="line.4906"></a>
+<span class="sourceLineNo">4907</span>          incMemStoreSize(mss);<a name="line.4907"></a>
+<span class="sourceLineNo">4908</span>          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());<a name="line.4908"></a>
+<span class="sourceLineNo">4909</span>          if (flush) {<a name="line.4909"></a>
+<span class="sourceLineNo">4910</span>            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,<a name="line.4910"></a>
+<span class="sourceLineNo">4911</span>              FlushLifeCycleTracker.DUMMY);<a name="line.4911"></a>
+<span class="sourceLineNo">4912</span>          }<a name="line.4912"></a>
+<span class="sourceLineNo">4913</span><a name="line.4913"></a>
+<span class="sourceLineNo">4914</span>          if (coprocessorHost != null) {<a name="line.4914"></a>
+<span class="sourceLineNo">4915</span>            coprocessorHost.postWALRestore(this.getRegionInfo(), key, val);<a name="line.4915"></a>
+<span class="sourceLineNo">4916</span>          }<a name="line.4916"></a>
+<span class="sourceLineNo">4917</span>        }<a name="line.4917"></a>
+<span class="sourceLineNo">4918</span><a name="line.4918"></a>
+<span class="sourceLineNo">4919</span>        if (coprocessorHost != null) {<a name="line.4919"></a>
+<span class="sourceLineNo">4920</span>          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);<a name="line.4920"></a>
+<span class="sourceLineNo">4921</span>        }<a name="line.4921"></a>
+<span class="sourceLineNo">4922</span>      } catch (EOFException eof) {<a name="line.4922"></a>
+<span class="sourceLineNo">4923</span>        Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4923"></a>
+<span class="sourceLineNo">4924</span>        msg = "EnLongAddered EOF. Most likely due to Master failure during " +<a name="line.4924"></a>
+<span class="sourceLineNo">4925</span>            "wal splitting, so we have this data in another edit.  " +<a name="line.4925"></a>
+<span class="sourceLineNo">4926</span>            "Continuing, but renaming " + edits + " as " + p;<a name="line.4926"></a>
+<span class="sourceLineNo">4927</span>        LOG.warn(msg, eof);<a name="line.4927"></a>
+<span class="sourceLineNo">4928</span>        status.abort(msg);<a name="line.4928"></a>
+<span class="sourceLineNo">4929</span>      } catch (IOException ioe) {<a name="line.4929"></a>
+<span class="sourceLineNo">4930</span>        // If the IOE resulted from bad file format,<a name="line.4930"></a>
+<span class="sourceLineNo">4931</span>        // then this problem is idempotent and retrying won't help<a name="line.4931"></a>
+<span class="sourceLineNo">4932</span>        if (ioe.getCause() instanceof ParseException) {<a name="line.4932"></a>
+<span class="sourceLineNo">4933</span>          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);<a name="line.4933"></a>
+<span class="sourceLineNo">4934</span>          msg = "File corruption enLongAddered!  " +<a name="line.4934"></a>
+<span class="sourceLineNo">4935</span>              "Continuing, but renaming " + edits + " as " + p;<a name="line.4935"></a>
+<span class="sourceLineNo">4936</span>          LOG.warn(msg, ioe);<a name="line.4936"></a>
+<span class="sourceLineNo">4937</span>          status.setStatus(msg);<a name="line.4937"></a>
+<span class="sourceLineNo">4938</span>        } else {<a name="line.4938"></a>
+<span class="sourceLineNo">4939</span>          status.abort(StringUtils.stringifyException(ioe));<a name="line.4939"></a>
+<span class="sourceLineNo">4940</span>          // other IO errors may be transient (bad network connection,<a name="line.4940"></a>
+<span class="sourceLineNo">4941</span>          // checksum exception on one datanode, etc).  throw &amp; retry<a name="line.4941"></a>
+<span class="sourceLineNo">4942</span>          throw ioe;<a name="line.4942"></a>
+<span class="sourceLineNo">4943</span>        }<a name="line.4943"></a>
 <span class="sourceLineNo">4944</span>      }<a name="line.4944"></a>
-<span class="sourceLineNo">4945</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4945"></a>
-<span class="sourceLineNo">4946</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4946"></a>
-<span class="sourceLineNo">4947</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4947"></a>
-<span class="sourceLineNo">4948</span>      status.markComplete(msg);<a name="line.4948"></a>
-<span class="sourceLineNo">4949</span>      LOG.debug(msg);<a name="line.4949"></a>
-<span class="sourceLineNo">4950</span>      return currentEditSeqId;<a name="line.4950"></a>
-<span class="sourceLineNo">4951</span>    } finally {<a name="line.4951"></a>
-<span class="sourceLineNo">4952</span>      status.cleanup();<a name="line.4952"></a>
-<span class="sourceLineNo">4953</span>      if (reader != null) {<a name="line.4953"></a>
-<span class="sourceLineNo">4954</span>         reader.close();<a name="line.4954"></a>
-<span class="sourceLineNo">4955</span>      }<a name="line.4955"></a>
-<span class="sourceLineNo">4956</span>    }<a name="line.4956"></a>
-<span class="sourceLineNo">4957</span>  }<a name="line.4957"></a>
-<span class="sourceLineNo">4958</span><a name="line.4958"></a>
-<span class="sourceLineNo">4959</span>  /**<a name="line.4959"></a>
-<span class="sourceLineNo">4960</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4960"></a>
-<span class="sourceLineNo">4961</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4961"></a>
-<span class="sourceLineNo">4962</span>   * See HBASE-2331.<a name="line.4962"></a>
-<span class="sourceLineNo">4963</span>   */<a name="line.4963"></a>
-<span class="sourceLineNo">4964</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4964"></a>
-<span class="sourceLineNo">4965</span>      boolean removeFiles, long replaySeqId)<a name="line.4965"></a>
-<span class="sourceLineNo">4966</span>      throws IOException {<a name="line.4966"></a>
-<span class="sourceLineNo">4967</span>    try {<a name="line.4967"></a>
-<span class="sourceLineNo">4968</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4968"></a>
-<span class="sourceLineNo">4969</span>        "Compaction marker from WAL ", compaction);<a name="line.4969"></a>
-<span class="sourceLineNo">4970</span>    } catch (WrongRegionException wre) {<a name="line.4970"></a>
-<span class="sourceLineNo">4971</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4971"></a>
-<span class="sourceLineNo">4972</span>        // skip the compaction marker since it is not for this region<a name="line.4972"></a>
-<span class="sourceLineNo">4973</span>        return;<a name="line.4973"></a>
-<span class="sourceLineNo">4974</span>      }<a name="line.4974"></a>
-<span class="sourceLineNo">4975</span>      throw wre;<a name="line.4975"></a>
-<span class="sourceLineNo">4976</span>    }<a name="line.4976"></a>
-<span class="sourceLineNo">4977</span><a name="line.4977"></a>
-<span class="sourceLineNo">4978</span>    synchronized (writestate) {<a name="line.4978"></a>
-<span class="sourceLineNo">4979</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4979"></a>
-<span class="sourceLineNo">4980</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4980"></a>
-<span class="sourceLineNo">4981</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4981"></a>
-<span class="sourceLineNo">4982</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4982"></a>
-<span class="sourceLineNo">4983</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4983"></a>
-<span class="sourceLineNo">4984</span>        return;<a name="line.4984"></a>
-<span class="sourceLineNo">4985</span>      }<a name="line.4985"></a>
-<span class="sourceLineNo">4986</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4986"></a>
-<span class="sourceLineNo">4987</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4987"></a>
-<span class="sourceLineNo">4988</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4988"></a>
-<span class="sourceLineNo">4989</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4989"></a>
-<span class="sourceLineNo">4990</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4990"></a>
-<span class="sourceLineNo">4991</span>        return;<a name="line.4991"></a>
-<span class="sourceLineNo">4992</span>      } else {<a name="line.4992"></a>
-<span class="sourceLineNo">4993</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4993"></a>
-<span class="sourceLineNo">4994</span>      }<a name="line.4994"></a>
-<span class="sourceLineNo">4995</span><a name="line.4995"></a>
-<span class="sourceLineNo">4996</span>      if (LOG.isDebugEnabled()) {<a name="line.4996"></a>
-<span class="sourceLineNo">4997</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.4997"></a>
-<span class="sourceLineNo">4998</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.4998"></a>
-<span class="sourceLineNo">4999</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.4999"></a>
-<span class="sourceLineNo">5000</span>            + lastReplayedOpenRegionSeqId);<a name="line.5000"></a>
-<span class="sourceLineNo">5001</span>      }<a name="line.5001"></a>
-<span class="sourceLineNo">5002</span><a name="line.5002"></a>
-<span class="sourceLineNo">5003</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5003"></a>
-<span class="sourceLineNo">5004</span>      try {<a name="line.5004"></a>
-<span class="sourceLineNo">5005</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5005"></a>
-<span class="sourceLineNo">5006</span>        if (store == null) {<a name="line.5006"></a>
-<span class="sourceLineNo">5007</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5007"></a>
-<span class="sourceLineNo">5008</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5008"></a>
-<span class="sourceLineNo">5009</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5009"></a>
-<span class="sourceLineNo">5010</span>          return;<a name="line.5010"></a>
-<span class="sourceLineNo">5011</span>        }<a name="line.5011"></a>
-<span class="sourceLineNo">5012</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5012"></a>
-<span class="sourceLineNo">5013</span>        logRegionFiles();<a name="line.5013"></a>
-<span class="sourceLineNo">5014</span>      } catch (FileNotFoundException ex) {<a name="line.5014"></a>
-<span class="sourceLineNo">5015</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5015"></a>
-<span class="sourceLineNo">5016</span>            + "At least one of the store files in compaction: "<a name="line.5016"></a>
-<span class="sourceLineNo">5017</span>            + TextFormat.shortDebugString(compaction)<a name="line.5017"></a>
-<span class="sourceLineNo">5018</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5018"></a>
-<span class="sourceLineNo">5019</span>      } finally {<a name="line.5019"></a>
-<span class="sourceLineNo">5020</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5020"></a>
-<span class="sourceLineNo">5021</span>      }<a name="line.5021"></a>
-<span class="sourceLineNo">5022</span>    }<a name="line.5022"></a>
-<span class="sourceLineNo">5023</span>  }<a name="line.5023"></a>
-<span class="sourceLineNo">5024</span><a name="line.5024"></a>
-<span class="sourceLineNo">5025</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5025"></a>
-<span class="sourceLineNo">5026</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5026"></a>
-<span class="sourceLineNo">5027</span>      "Flush marker from WAL ", flush);<a name="line.5027"></a>
-<span class="sourceLineNo">5028</span><a name="line.5028"></a>
-<span class="sourceLineNo">5029</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5029"></a>
-<span class="sourceLineNo">5030</span>      return; // if primary nothing to do<a name="line.5030"></a>
-<span class="sourceLineNo">5031</span>    }<a name="line.5031"></a>
-<span class="sourceLineNo">5032</span><a name="line.5032"></a>
-<span class="sourceLineNo">5033</span>    if (LOG.isDebugEnabled()) {<a name="line.5033"></a>
-<span class="sourceLineNo">5034</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5034"></a>
-<span class="sourceLineNo">5035</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5035"></a>
-<span class="sourceLineNo">5036</span>    }<a name="line.5036"></a>
-<span class="sourceLineNo">5037</span><a name="line.5037"></a>
-<span class="sourceLineNo">5038</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5038"></a>
-<span class="sourceLineNo">5039</span>    try {<a name="line.5039"></a>
-<span class="sourceLineNo">5040</span>      FlushAction action = flush.getAction();<a name="line.5040"></a>
-<span class="sourceLineNo">5041</span>      switch (action) {<a name="line.5041"></a>
-<span class="sourceLineNo">5042</span>      case START_FLUSH:<a name="line.5042"></a>
-<span class="sourceLineNo">5043</span>        replayWALFlushStartMarker(flush);<a name="line.5043"></a>
-<span class="sourceLineNo">5044</span>        break;<a name="line.5044"></a>
-<span class="sourceLineNo">5045</span>      case COMMIT_FLUSH:<a name="line.5045"></a>
-<span class="sourceLineNo">5046</span>        replayWALFlushCommitMarker(flush);<a name="line.5046"></a>
+<span class="sourceLineNo">4945</span>      if (reporter != null &amp;&amp; !reported_once) {<a name="line.4945"></a>
+<span class="sourceLineNo">4946</span>        reporter.progress();<a name="line.4946"></a>
+<span class="sourceLineNo">4947</span>      }<a name="line.4947"></a>
+<span class="sourceLineNo">4948</span>      msg = "Applied " + editsCount + ", skipped " + skippedEdits +<a name="line.4948"></a>
+<span class="sourceLineNo">4949</span>        ", firstSequenceIdInLog=" + firstSeqIdInLog +<a name="line.4949"></a>
+<span class="sourceLineNo">4950</span>        ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;<a name="line.4950"></a>
+<span class="sourceLineNo">4951</span>      status.markComplete(msg);<a name="line.4951"></a>
+<span class="sourceLineNo">4952</span>      LOG.debug(msg);<a name="line.4952"></a>
+<span class="sourceLineNo">4953</span>      return currentEditSeqId;<a name="line.4953"></a>
+<span class="sourceLineNo">4954</span>    } finally {<a name="line.4954"></a>
+<span class="sourceLineNo">4955</span>      status.cleanup();<a name="line.4955"></a>
+<span class="sourceLineNo">4956</span>      if (reader != null) {<a name="line.4956"></a>
+<span class="sourceLineNo">4957</span>         reader.close();<a name="line.4957"></a>
+<span class="sourceLineNo">4958</span>      }<a name="line.4958"></a>
+<span class="sourceLineNo">4959</span>    }<a name="line.4959"></a>
+<span class="sourceLineNo">4960</span>  }<a name="line.4960"></a>
+<span class="sourceLineNo">4961</span><a name="line.4961"></a>
+<span class="sourceLineNo">4962</span>  /**<a name="line.4962"></a>
+<span class="sourceLineNo">4963</span>   * Call to complete a compaction. Its for the case where we find in the WAL a compaction<a name="line.4963"></a>
+<span class="sourceLineNo">4964</span>   * that was not finished.  We could find one recovering a WAL after a regionserver crash.<a name="line.4964"></a>
+<span class="sourceLineNo">4965</span>   * See HBASE-2331.<a name="line.4965"></a>
+<span class="sourceLineNo">4966</span>   */<a name="line.4966"></a>
+<span class="sourceLineNo">4967</span>  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,<a name="line.4967"></a>
+<span class="sourceLineNo">4968</span>      boolean removeFiles, long replaySeqId)<a name="line.4968"></a>
+<span class="sourceLineNo">4969</span>      throws IOException {<a name="line.4969"></a>
+<span class="sourceLineNo">4970</span>    try {<a name="line.4970"></a>
+<span class="sourceLineNo">4971</span>      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),<a name="line.4971"></a>
+<span class="sourceLineNo">4972</span>        "Compaction marker from WAL ", compaction);<a name="line.4972"></a>
+<span class="sourceLineNo">4973</span>    } catch (WrongRegionException wre) {<a name="line.4973"></a>
+<span class="sourceLineNo">4974</span>      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.4974"></a>
+<span class="sourceLineNo">4975</span>        // skip the compaction marker since it is not for this region<a name="line.4975"></a>
+<span class="sourceLineNo">4976</span>        return;<a name="line.4976"></a>
+<span class="sourceLineNo">4977</span>      }<a name="line.4977"></a>
+<span class="sourceLineNo">4978</span>      throw wre;<a name="line.4978"></a>
+<span class="sourceLineNo">4979</span>    }<a name="line.4979"></a>
+<span class="sourceLineNo">4980</span><a name="line.4980"></a>
+<span class="sourceLineNo">4981</span>    synchronized (writestate) {<a name="line.4981"></a>
+<span class="sourceLineNo">4982</span>      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {<a name="line.4982"></a>
+<span class="sourceLineNo">4983</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4983"></a>
+<span class="sourceLineNo">4984</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4984"></a>
+<span class="sourceLineNo">4985</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4985"></a>
+<span class="sourceLineNo">4986</span>            + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.4986"></a>
+<span class="sourceLineNo">4987</span>        return;<a name="line.4987"></a>
+<span class="sourceLineNo">4988</span>      }<a name="line.4988"></a>
+<span class="sourceLineNo">4989</span>      if (replaySeqId &lt; lastReplayedCompactionSeqId) {<a name="line.4989"></a>
+<span class="sourceLineNo">4990</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.4990"></a>
+<span class="sourceLineNo">4991</span>            + "Skipping replaying compaction event :" + TextFormat.shortDebugString(compaction)<a name="line.4991"></a>
+<span class="sourceLineNo">4992</span>            + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.4992"></a>
+<span class="sourceLineNo">4993</span>            + "lastReplayedCompactionSeqId of " + lastReplayedCompactionSeqId);<a name="line.4993"></a>
+<span class="sourceLineNo">4994</span>        return;<a name="line.4994"></a>
+<span class="sourceLineNo">4995</span>      } else {<a name="line.4995"></a>
+<span class="sourceLineNo">4996</span>        lastReplayedCompactionSeqId = replaySeqId;<a name="line.4996"></a>
+<span class="sourceLineNo">4997</span>      }<a name="line.4997"></a>
+<span class="sourceLineNo">4998</span><a name="line.4998"></a>
+<span class="sourceLineNo">4999</span>      if (LOG.isDebugEnabled()) {<a name="line.4999"></a>
+<span class="sourceLineNo">5000</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5000"></a>
+<span class="sourceLineNo">5001</span>            + "Replaying compaction marker " + TextFormat.shortDebugString(compaction)<a name="line.5001"></a>
+<span class="sourceLineNo">5002</span>            + " with seqId=" + replaySeqId + " and lastReplayedOpenRegionSeqId="<a name="line.5002"></a>
+<span class="sourceLineNo">5003</span>            + lastReplayedOpenRegionSeqId);<a name="line.5003"></a>
+<span class="sourceLineNo">5004</span>      }<a name="line.5004"></a>
+<span class="sourceLineNo">5005</span><a name="line.5005"></a>
+<span class="sourceLineNo">5006</span>      startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5006"></a>
+<span class="sourceLineNo">5007</span>      try {<a name="line.5007"></a>
+<span class="sourceLineNo">5008</span>        HStore store = this.getStore(compaction.getFamilyName().toByteArray());<a name="line.5008"></a>
+<span class="sourceLineNo">5009</span>        if (store == null) {<a name="line.5009"></a>
+<span class="sourceLineNo">5010</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5010"></a>
+<span class="sourceLineNo">5011</span>              + "Found Compaction WAL edit for deleted family:"<a name="line.5011"></a>
+<span class="sourceLineNo">5012</span>              + Bytes.toString(compaction.getFamilyName().toByteArray()));<a name="line.5012"></a>
+<span class="sourceLineNo">5013</span>          return;<a name="line.5013"></a>
+<span class="sourceLineNo">5014</span>        }<a name="line.5014"></a>
+<span class="sourceLineNo">5015</span>        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);<a name="line.5015"></a>
+<span class="sourceLineNo">5016</span>        logRegionFiles();<a name="line.5016"></a>
+<span class="sourceLineNo">5017</span>      } catch (FileNotFoundException ex) {<a name="line.5017"></a>
+<span class="sourceLineNo">5018</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5018"></a>
+<span class="sourceLineNo">5019</span>            + "At least one of the store files in compaction: "<a name="line.5019"></a>
+<span class="sourceLineNo">5020</span>            + TextFormat.shortDebugString(compaction)<a name="line.5020"></a>
+<span class="sourceLineNo">5021</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5021"></a>
+<span class="sourceLineNo">5022</span>      } finally {<a name="line.5022"></a>
+<span class="sourceLineNo">5023</span>        closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5023"></a>
+<span class="sourceLineNo">5024</span>      }<a name="line.5024"></a>
+<span class="sourceLineNo">5025</span>    }<a name="line.5025"></a>
+<span class="sourceLineNo">5026</span>  }<a name="line.5026"></a>
+<span class="sourceLineNo">5027</span><a name="line.5027"></a>
+<span class="sourceLineNo">5028</span>  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {<a name="line.5028"></a>
+<span class="sourceLineNo">5029</span>    checkTargetRegion(flush.getEncodedRegionName().toByteArray(),<a name="line.5029"></a>
+<span class="sourceLineNo">5030</span>      "Flush marker from WAL ", flush);<a name="line.5030"></a>
+<span class="sourceLineNo">5031</span><a name="line.5031"></a>
+<span class="sourceLineNo">5032</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5032"></a>
+<span class="sourceLineNo">5033</span>      return; // if primary nothing to do<a name="line.5033"></a>
+<span class="sourceLineNo">5034</span>    }<a name="line.5034"></a>
+<span class="sourceLineNo">5035</span><a name="line.5035"></a>
+<span class="sourceLineNo">5036</span>    if (LOG.isDebugEnabled()) {<a name="line.5036"></a>
+<span class="sourceLineNo">5037</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5037"></a>
+<span class="sourceLineNo">5038</span>          + "Replaying flush marker " + TextFormat.shortDebugString(flush));<a name="line.5038"></a>
+<span class="sourceLineNo">5039</span>    }<a name="line.5039"></a>
+<span class="sourceLineNo">5040</span><a name="line.5040"></a>
+<span class="sourceLineNo">5041</span>    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close<a name="line.5041"></a>
+<span class="sourceLineNo">5042</span>    try {<a name="line.5042"></a>
+<span class="sourceLineNo">5043</span>      FlushAction action = flush.getAction();<a name="line.5043"></a>
+<span class="sourceLineNo">5044</span>      switch (action) {<a name="line.5044"></a>
+<span class="sourceLineNo">5045</span>      case START_FLUSH:<a name="line.5045"></a>
+<span class="sourceLineNo">5046</span>        replayWALFlushStartMarker(flush);<a name="line.5046"></a>
 <span class="sourceLineNo">5047</span>        break;<a name="line.5047"></a>
-<span class="sourceLineNo">5048</span>      case ABORT_FLUSH:<a name="line.5048"></a>
-<span class="sourceLineNo">5049</span>        replayWALFlushAbortMarker(flush);<a name="line.5049"></a>
+<span class="sourceLineNo">5048</span>      case COMMIT_FLUSH:<a name="line.5048"></a>
+<span class="sourceLineNo">5049</span>        replayWALFlushCommitMarker(flush);<a name="line.5049"></a>
 <span class="sourceLineNo">5050</span>        break;<a name="line.5050"></a>
-<span class="sourceLineNo">5051</span>      case CANNOT_FLUSH:<a name="line.5051"></a>
-<span class="sourceLineNo">5052</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5052"></a>
+<span class="sourceLineNo">5051</span>      case ABORT_FLUSH:<a name="line.5051"></a>
+<span class="sourceLineNo">5052</span>        replayWALFlushAbortMarker(flush);<a name="line.5052"></a>
 <span class="sourceLineNo">5053</span>        break;<a name="line.5053"></a>
-<span class="sourceLineNo">5054</span>      default:<a name="line.5054"></a>
-<span class="sourceLineNo">5055</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5055"></a>
-<span class="sourceLineNo">5056</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5056"></a>
-<span class="sourceLineNo">5057</span>          TextFormat.shortDebugString(flush));<a name="line.5057"></a>
-<span class="sourceLineNo">5058</span>        break;<a name="line.5058"></a>
-<span class="sourceLineNo">5059</span>      }<a name="line.5059"></a>
-<span class="sourceLineNo">5060</span><a name="line.5060"></a>
-<span class="sourceLineNo">5061</span>      logRegionFiles();<a name="line.5061"></a>
-<span class="sourceLineNo">5062</span>    } finally {<a name="line.5062"></a>
-<span class="sourceLineNo">5063</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5063"></a>
-<span class="sourceLineNo">5064</span>    }<a name="line.5064"></a>
-<span class="sourceLineNo">5065</span>  }<a name="line.5065"></a>
-<span class="sourceLineNo">5066</span><a name="line.5066"></a>
-<span class="sourceLineNo">5067</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5067"></a>
-<span class="sourceLineNo">5068</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5068"></a>
-<span class="sourceLineNo">5069</span>   * edit (because the events may be coming out of order).<a name="line.5069"></a>
-<span class="sourceLineNo">5070</span>   */<a name="line.5070"></a>
-<span class="sourceLineNo">5071</span>  @VisibleForTesting<a name="line.5071"></a>
-<span class="sourceLineNo">5072</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5072"></a>
-<span class="sourceLineNo">5073</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5073"></a>
-<span class="sourceLineNo">5074</span><a name="line.5074"></a>
-<span class="sourceLineNo">5075</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5075"></a>
-<span class="sourceLineNo">5076</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5076"></a>
-<span class="sourceLineNo">5077</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5077"></a>
-<span class="sourceLineNo">5078</span>      HStore store = getStore(family);<a name="line.5078"></a>
-<span class="sourceLineNo">5079</span>      if (store == null) {<a name="line.5079"></a>
-<span class="sourceLineNo">5080</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5080"></a>
-<span class="sourceLineNo">5081</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5081"></a>
-<span class="sourceLineNo">5082</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5082"></a>
-<span class="sourceLineNo">5083</span>        continue;<a name="line.5083"></a>
-<span class="sourceLineNo">5084</span>      }<a name="line.5084"></a>
-<span class="sourceLineNo">5085</span>      storesToFlush.add(store);<a name="line.5085"></a>
-<span class="sourceLineNo">5086</span>    }<a name="line.5086"></a>
-<span class="sourceLineNo">5087</span><a name="line.5087"></a>
-<span class="sourceLineNo">5088</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5088"></a>
-<span class="sourceLineNo">5089</span><a name="line.5089"></a>
-<span class="sourceLineNo">5090</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5090"></a>
-<span class="sourceLineNo">5091</span>    // (flush, compaction, region open etc)<a name="line.5091"></a>
-<span class="sourceLineNo">5092</span>    synchronized (writestate) {<a name="line.5092"></a>
-<span class="sourceLineNo">5093</span>      try {<a name="line.5093"></a>
-<span class="sourceLineNo">5094</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5094"></a>
-<span class="sourceLineNo">5095</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5095"></a>
-<span class="sourceLineNo">5096</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5096"></a>
-<span class="sourceLineNo">5097</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5097"></a>
-<span class="sourceLineNo">5098</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5098"></a>
-<span class="sourceLineNo">5099</span>          return null;<a name="line.5099"></a>
-<span class="sourceLineNo">5100</span>        }<a name="line.5100"></a>
-<span class="sourceLineNo">5101</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5101"></a>
-<span class="sourceLineNo">5102</span>          numMutationsWithoutWAL.reset();<a name="line.5102"></a>
-<span class="sourceLineNo">5103</span>          dataInMemoryWithoutWAL.reset();<a name="line.5103"></a>
-<span class="sourceLineNo">5104</span>        }<a name="line.5104"></a>
-<span class="sourceLineNo">5105</span><a name="line.5105"></a>
-<span class="sourceLineNo">5106</span>        if (!writestate.flushing) {<a name="line.5106"></a>
-<span class="sourceLineNo">5107</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5107"></a>
-<span class="sourceLineNo">5108</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5108"></a>
-<span class="sourceLineNo">5109</span><a name="line.5109"></a>
-<span class="sourceLineNo">5110</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5110"></a>
-<span class="sourceLineNo">5111</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5111"></a>
-<span class="sourceLineNo">5112</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5112"></a>
-<span class="sourceLineNo">5113</span>          if (prepareResult.result == null) {<a name="line.5113"></a>
-<span class="sourceLineNo">5114</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5114"></a>
-<span class="sourceLineNo">5115</span>            this.writestate.flushing = true;<a name="line.5115"></a>
-<span class="sourceLineNo">5116</span>            this.prepareFlushResult = prepareResult;<a name="line.5116"></a>
-<span class="sourceLineNo">5117</span>            status.markComplete("Flush prepare successful");<a name="line.5117"></a>
-<span class="sourceLineNo">5118</span>            if (LOG.isDebugEnabled()) {<a name="line.5118"></a>
-<span class="sourceLineNo">5119</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5119"></a>
-<span class="sourceLineNo">5120</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5120"></a>
-<span class="sourceLineNo">5121</span>            }<a name="line.5121"></a>
-<span class="sourceLineNo">5122</span>          } else {<a name="line.5122"></a>
-<span class="sourceLineNo">5123</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5123"></a>
-<span class="sourceLineNo">5124</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5124"></a>
-<span class="sourceLineNo">5125</span>            if (prepareResult.getResult().getResult() ==<a name="line.5125"></a>
-<span class="sourceLineNo">5126</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5126"></a>
-<span class="sourceLineNo">5127</span>              this.writestate.flushing = true;<a name="line.5127"></a>
-<span class="sourceLineNo">5128</span>              this.prepareFlushResult = prepareResult;<a name="line.5128"></a>
-<span class="sourceLineNo">5129</span>              if (LOG.isDebugEnabled()) {<a name="line.5129"></a>
-<span class="sourceLineNo">5130</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5130"></a>
-<span class="sourceLineNo">5131</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5131"></a>
-<span class="sourceLineNo">5132</span>              }<a name="line.5132"></a>
-<span class="sourceLineNo">5133</span>            }<a name="line.5133"></a>
-<span class="sourceLineNo">5134</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5134"></a>
-<span class="sourceLineNo">5135</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5135"></a>
-<span class="sourceLineNo">5136</span>          }<a name="line.5136"></a>
-<span class="sourceLineNo">5137</span>          return prepareResult;<a name="line.5137"></a>
-<span class="sourceLineNo">5138</span>        } else {<a name="line.5138"></a>
-<span class="sourceLineNo">5139</span>          // we already have an active snapshot.<a name="line.5139"></a>
-<span class="sourceLineNo">5140</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5140"></a>
-<span class="sourceLineNo">5141</span>            // They define the same flush. Log and continue.<a name="line.5141"></a>
-<span class="sourceLineNo">5142</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5142"></a>
-<span class="sourceLineNo">5143</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5143"></a>
-<span class="sourceLineNo">5144</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5144"></a>
-<span class="sourceLineNo">5145</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5145"></a>
-<span class="sourceLineNo">5146</span>            // ignore<a name="line.5146"></a>
-<span class="sourceLineNo">5147</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5147"></a>
-<span class="sourceLineNo">5148</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5148"></a>
-<span class="sourceLineNo">5149</span>            // ignore this prepare flush request.<a name="line.5149"></a>
-<span class="sourceLineNo">5150</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5150"></a>
-<span class="sourceLineNo">5151</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5151"></a>
-<span class="sourceLineNo">5152</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5152"></a>
-<span class="sourceLineNo">5153</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5153"></a>
-<span class="sourceLineNo">5154</span>            // ignore<a name="line.5154"></a>
-<span class="sourceLineNo">5155</span>          } else {<a name="line.5155"></a>
-<span class="sourceLineNo">5156</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5156"></a>
-<span class="sourceLineNo">5157</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5157"></a>
-<span class="sourceLineNo">5158</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5158"></a>
-<span class="sourceLineNo">5159</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5159"></a>
-<span class="sourceLineNo">5160</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5160"></a>
-<span class="sourceLineNo">5161</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5161"></a>
-<span class="sourceLineNo">5162</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5162"></a>
-<span class="sourceLineNo">5163</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5163"></a>
-<span class="sourceLineNo">5164</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5164"></a>
-<span class="sourceLineNo">5165</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5165"></a>
-<span class="sourceLineNo">5166</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5166"></a>
-<span class="sourceLineNo">5167</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5167"></a>
-<span class="sourceLineNo">5168</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5168"></a>
-<span class="sourceLineNo">5169</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5169"></a>
-<span class="sourceLineNo">5170</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5170"></a>
-<span class="sourceLineNo">5171</span>            // further prapare + commit flush is seen and replayed.<a name="line.5171"></a>
-<span class="sourceLineNo">5172</span>          }<a name="line.5172"></a>
-<span class="sourceLineNo">5173</span>        }<a name="line.5173"></a>
-<span class="sourceLineNo">5174</span>      } finally {<a name="line.5174"></a>
-<span class="sourceLineNo">5175</span>        status.cleanup();<a name="line.5175"></a>
-<span class="sourceLineNo">5176</span>        writestate.notifyAll();<a name="line.5176"></a>
-<span class="sourceLineNo">5177</span>      }<a name="line.5177"></a>
-<span class="sourceLineNo">5178</span>    }<a name="line.5178"></a>
-<span class="sourceLineNo">5179</span>    return null;<a name="line.5179"></a>
-<span class="sourceLineNo">5180</span>  }<a name="line.5180"></a>
-<span class="sourceLineNo">5181</span><a name="line.5181"></a>
-<span class="sourceLineNo">5182</span>  @VisibleForTesting<a name="line.5182"></a>
-<span class="sourceLineNo">5183</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5183"></a>
-<span class="sourceLineNo">5184</span>    justification="Intentional; post memstore flush")<a name="line.5184"></a>
-<span class="sourceLineNo">5185</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5185"></a>
-<span class="sourceLineNo">5186</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5186"></a>
-<span class="sourceLineNo">5187</span><a name="line.5187"></a>
-<span class="sourceLineNo">5188</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5188"></a>
-<span class="sourceLineNo">5189</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5189"></a>
-<span class="sourceLineNo">5190</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5190"></a>
-<span class="sourceLineNo">5191</span>    // the original seqIds.<a name="line.5191"></a>
-<span class="sourceLineNo">5192</span>    synchronized (writestate) {<a name="line.5192"></a>
-<span class="sourceLineNo">5193</span>      try {<a name="line.5193"></a>
-<span class="sourceLineNo">5194</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5194"></a>
-<span class="sourceLineNo">5195</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5195"></a>
-<span class="sourceLineNo">5196</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5196"></a>
-<span class="sourceLineNo">5197</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5197"></a>
-<span class="sourceLineNo">5198</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5198"></a>
-<span class="sourceLineNo">5199</span>          return;<a name="line.5199"></a>
-<span class="sourceLineNo">5200</span>        }<a name="line.5200"></a>
-<span class="sourceLineNo">5201</span><a name="line.5201"></a>
-<span class="sourceLineNo">5202</span>        if (writestate.flushing) {<a name="line.5202"></a>
-<span class="sourceLineNo">5203</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5203"></a>
-<span class="sourceLineNo">5204</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5204"></a>
-<span class="sourceLineNo">5205</span>            if (LOG.isDebugEnabled()) {<a name="line.5205"></a>
-<span class="sourceLineNo">5206</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5206"></a>
-<span class="sourceLineNo">5207</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5207"></a>
-<span class="sourceLineNo">5208</span>                  + " and a previous prepared snapshot was found");<a name="line.5208"></a>
-<span class="sourceLineNo">5209</span>            }<a name="line.5209"></a>
-<span class="sourceLineNo">5210</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5210"></a>
-<span class="sourceLineNo">5211</span>            // corresponding to the same seqId.<a name="line.5211"></a>
-<span class="sourceLineNo">5212</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5212"></a>
-<span class="sourceLineNo">5213</span><a name="line.5213"></a>
-<span class="sourceLineNo">5214</span>            // Set down the memstore size by amount of flush.<a name="line.5214"></a>
-<span class="sourceLineNo">5215</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5215"></a>
-<span class="sourceLineNo">5216</span>            this.prepareFlushResult = null;<a name="line.5216"></a>
-<span class="sourceLineNo">5217</span>            writestate.flushing = false;<a name="line.5217"></a>
-<span class="sourceLineNo">5218</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5218"></a>
-<span class="sourceLineNo">5219</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5219"></a>
-<span class="sourceLineNo">5220</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5220"></a>
-<span class="sourceLineNo">5221</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5221"></a>
-<span class="sourceLineNo">5222</span>            // will not drop the memstore<a name="line.5222"></a>
-<span class="sourceLineNo">5223</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5223"></a>
-<span class="sourceLineNo">5224</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5224"></a>
-<span class="sourceLineNo">5225</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5225"></a>
-<span class="sourceLineNo">5226</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5226"></a>
-<span class="sourceLineNo">5227</span>                +"  prepared memstore snapshot");<a name="line.5227"></a>
-<span class="sourceLineNo">5228</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5228"></a>
-<span class="sourceLineNo">5229</span><a name="line.5229"></a>
-<span class="sourceLineNo">5230</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5230"></a>
-<span class="sourceLineNo">5231</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5231"></a>
-<span class="sourceLineNo">5232</span>          } else {<a name="line.5232"></a>
-<span class="sourceLineNo">5233</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5233"></a>
-<span class="sourceLineNo">5234</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5234"></a>
-<span class="sourceLineNo">5235</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5235"></a>
-<span class="sourceLineNo">5236</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5236"></a>
-<span class="sourceLineNo">5237</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5237"></a>
-<span class="sourceLineNo">5238</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5238"></a>
-<span class="sourceLineNo">5239</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5239"></a>
-<span class="sourceLineNo">5240</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5240"></a>
-<span class="sourceLineNo">5241</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5241"></a>
-<span class="sourceLineNo">5242</span>                +" memstore snapshot");<a name="line.5242"></a>
-<span class="sourceLineNo">5243</span><a name="line.5243"></a>
-<span class="sourceLineNo">5244</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5244"></a>
-<span class="sourceLineNo">5245</span><a name="line.5245"></a>
-<span class="sourceLineNo">5246</span>            // Set down the memstore size by amount of flush.<a name="line.5246"></a>
-<span class="sourceLineNo">5247</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5247"></a>
+<span class="sourceLineNo">5054</span>      case CANNOT_FLUSH:<a name="line.5054"></a>
+<span class="sourceLineNo">5055</span>        replayWALFlushCannotFlushMarker(flush, replaySeqId);<a name="line.5055"></a>
+<span class="sourceLineNo">5056</span>        break;<a name="line.5056"></a>
+<span class="sourceLineNo">5057</span>      default:<a name="line.5057"></a>
+<span class="sourceLineNo">5058</span>        LOG.warn(getRegionInfo().getEncodedName() + " : " +<a name="line.5058"></a>
+<span class="sourceLineNo">5059</span>          "Received a flush event with unknown action, ignoring. " +<a name="line.5059"></a>
+<span class="sourceLineNo">5060</span>          TextFormat.shortDebugString(flush));<a name="line.5060"></a>
+<span class="sourceLineNo">5061</span>        break;<a name="line.5061"></a>
+<span class="sourceLineNo">5062</span>      }<a name="line.5062"></a>
+<span class="sourceLineNo">5063</span><a name="line.5063"></a>
+<span class="sourceLineNo">5064</span>      logRegionFiles();<a name="line.5064"></a>
+<span class="sourceLineNo">5065</span>    } finally {<a name="line.5065"></a>
+<span class="sourceLineNo">5066</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5066"></a>
+<span class="sourceLineNo">5067</span>    }<a name="line.5067"></a>
+<span class="sourceLineNo">5068</span>  }<a name="line.5068"></a>
+<span class="sourceLineNo">5069</span><a name="line.5069"></a>
+<span class="sourceLineNo">5070</span>  /** Replay the flush marker from primary region by creating a corresponding snapshot of<a name="line.5070"></a>
+<span class="sourceLineNo">5071</span>   * the store memstores, only if the memstores do not have a higher seqId from an earlier wal<a name="line.5071"></a>
+<span class="sourceLineNo">5072</span>   * edit (because the events may be coming out of order).<a name="line.5072"></a>
+<span class="sourceLineNo">5073</span>   */<a name="line.5073"></a>
+<span class="sourceLineNo">5074</span>  @VisibleForTesting<a name="line.5074"></a>
+<span class="sourceLineNo">5075</span>  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {<a name="line.5075"></a>
+<span class="sourceLineNo">5076</span>    long flushSeqId = flush.getFlushSequenceNumber();<a name="line.5076"></a>
+<span class="sourceLineNo">5077</span><a name="line.5077"></a>
+<span class="sourceLineNo">5078</span>    HashSet&lt;HStore&gt; storesToFlush = new HashSet&lt;&gt;();<a name="line.5078"></a>
+<span class="sourceLineNo">5079</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5079"></a>
+<span class="sourceLineNo">5080</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5080"></a>
+<span class="sourceLineNo">5081</span>      HStore store = getStore(family);<a name="line.5081"></a>
+<span class="sourceLineNo">5082</span>      if (store == null) {<a name="line.5082"></a>
+<span class="sourceLineNo">5083</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5083"></a>
+<span class="sourceLineNo">5084</span>          + "Received a flush start marker from primary, but the family is not found. Ignoring"<a name="line.5084"></a>
+<span class="sourceLineNo">5085</span>          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));<a name="line.5085"></a>
+<span class="sourceLineNo">5086</span>        continue;<a name="line.5086"></a>
+<span class="sourceLineNo">5087</span>      }<a name="line.5087"></a>
+<span class="sourceLineNo">5088</span>      storesToFlush.add(store);<a name="line.5088"></a>
+<span class="sourceLineNo">5089</span>    }<a name="line.5089"></a>
+<span class="sourceLineNo">5090</span><a name="line.5090"></a>
+<span class="sourceLineNo">5091</span>    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);<a name="line.5091"></a>
+<span class="sourceLineNo">5092</span><a name="line.5092"></a>
+<span class="sourceLineNo">5093</span>    // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5093"></a>
+<span class="sourceLineNo">5094</span>    // (flush, compaction, region open etc)<a name="line.5094"></a>
+<span class="sourceLineNo">5095</span>    synchronized (writestate) {<a name="line.5095"></a>
+<span class="sourceLineNo">5096</span>      try {<a name="line.5096"></a>
+<span class="sourceLineNo">5097</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5097"></a>
+<span class="sourceLineNo">5098</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5098"></a>
+<span class="sourceLineNo">5099</span>              + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5099"></a>
+<span class="sourceLineNo">5100</span>              + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5100"></a>
+<span class="sourceLineNo">5101</span>              + " of " + lastReplayedOpenRegionSeqId);<a name="line.5101"></a>
+<span class="sourceLineNo">5102</span>          return null;<a name="line.5102"></a>
+<span class="sourceLineNo">5103</span>        }<a name="line.5103"></a>
+<span class="sourceLineNo">5104</span>        if (numMutationsWithoutWAL.sum() &gt; 0) {<a name="line.5104"></a>
+<span class="sourceLineNo">5105</span>          numMutationsWithoutWAL.reset();<a name="line.5105"></a>
+<span class="sourceLineNo">5106</span>          dataInMemoryWithoutWAL.reset();<a name="line.5106"></a>
+<span class="sourceLineNo">5107</span>        }<a name="line.5107"></a>
+<span class="sourceLineNo">5108</span><a name="line.5108"></a>
+<span class="sourceLineNo">5109</span>        if (!writestate.flushing) {<a name="line.5109"></a>
+<span class="sourceLineNo">5110</span>          // we do not have an active snapshot and corresponding this.prepareResult. This means<a name="line.5110"></a>
+<span class="sourceLineNo">5111</span>          // we can just snapshot our memstores and continue as normal.<a name="line.5111"></a>
+<span class="sourceLineNo">5112</span><a name="line.5112"></a>
+<span class="sourceLineNo">5113</span>          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal<a name="line.5113"></a>
+<span class="sourceLineNo">5114</span>          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,<a name="line.5114"></a>
+<span class="sourceLineNo">5115</span>            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);<a name="line.5115"></a>
+<span class="sourceLineNo">5116</span>          if (prepareResult.result == null) {<a name="line.5116"></a>
+<span class="sourceLineNo">5117</span>            // save the PrepareFlushResult so that we can use it later from commit flush<a name="line.5117"></a>
+<span class="sourceLineNo">5118</span>            this.writestate.flushing = true;<a name="line.5118"></a>
+<span class="sourceLineNo">5119</span>            this.prepareFlushResult = prepareResult;<a name="line.5119"></a>
+<span class="sourceLineNo">5120</span>            status.markComplete("Flush prepare successful");<a name="line.5120"></a>
+<span class="sourceLineNo">5121</span>            if (LOG.isDebugEnabled()) {<a name="line.5121"></a>
+<span class="sourceLineNo">5122</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5122"></a>
+<span class="sourceLineNo">5123</span>                  + " Prepared flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5123"></a>
+<span class="sourceLineNo">5124</span>            }<a name="line.5124"></a>
+<span class="sourceLineNo">5125</span>          } else {<a name="line.5125"></a>
+<span class="sourceLineNo">5126</span>            // special case empty memstore. We will still save the flush result in this case, since<a name="line.5126"></a>
+<span class="sourceLineNo">5127</span>            // our memstore ie empty, but the primary is still flushing<a name="line.5127"></a>
+<span class="sourceLineNo">5128</span>            if (prepareResult.getResult().getResult() ==<a name="line.5128"></a>
+<span class="sourceLineNo">5129</span>                  FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.5129"></a>
+<span class="sourceLineNo">5130</span>              this.writestate.flushing = true;<a name="line.5130"></a>
+<span class="sourceLineNo">5131</span>              this.prepareFlushResult = prepareResult;<a name="line.5131"></a>
+<span class="sourceLineNo">5132</span>              if (LOG.isDebugEnabled()) {<a name="line.5132"></a>
+<span class="sourceLineNo">5133</span>                LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5133"></a>
+<span class="sourceLineNo">5134</span>                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());<a name="line.5134"></a>
+<span class="sourceLineNo">5135</span>              }<a name="line.5135"></a>
+<span class="sourceLineNo">5136</span>            }<a name="line.5136"></a>
+<span class="sourceLineNo">5137</span>            status.abort("Flush prepare failed with " + prepareResult.result);<a name="line.5137"></a>
+<span class="sourceLineNo">5138</span>            // nothing much to do. prepare flush failed because of some reason.<a name="line.5138"></a>
+<span class="sourceLineNo">5139</span>          }<a name="line.5139"></a>
+<span class="sourceLineNo">5140</span>          return prepareResult;<a name="line.5140"></a>
+<span class="sourceLineNo">5141</span>        } else {<a name="line.5141"></a>
+<span class="sourceLineNo">5142</span>          // we already have an active snapshot.<a name="line.5142"></a>
+<span class="sourceLineNo">5143</span>          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {<a name="line.5143"></a>
+<span class="sourceLineNo">5144</span>            // They define the same flush. Log and continue.<a name="line.5144"></a>
+<span class="sourceLineNo">5145</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5145"></a>
+<span class="sourceLineNo">5146</span>                + "Received a flush prepare marker with the same seqId: " +<a name="line.5146"></a>
+<span class="sourceLineNo">5147</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5147"></a>
+<span class="sourceLineNo">5148</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5148"></a>
+<span class="sourceLineNo">5149</span>            // ignore<a name="line.5149"></a>
+<span class="sourceLineNo">5150</span>          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {<a name="line.5150"></a>
+<span class="sourceLineNo">5151</span>            // We received a flush with a smaller seqNum than what we have prepared. We can only<a name="line.5151"></a>
+<span class="sourceLineNo">5152</span>            // ignore this prepare flush request.<a name="line.5152"></a>
+<span class="sourceLineNo">5153</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5153"></a>
+<span class="sourceLineNo">5154</span>                + "Received a flush prepare marker with a smaller seqId: " +<a name="line.5154"></a>
+<span class="sourceLineNo">5155</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5155"></a>
+<span class="sourceLineNo">5156</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5156"></a>
+<span class="sourceLineNo">5157</span>            // ignore<a name="line.5157"></a>
+<span class="sourceLineNo">5158</span>          } else {<a name="line.5158"></a>
+<span class="sourceLineNo">5159</span>            // We received a flush with a larger seqNum than what we have prepared<a name="line.5159"></a>
+<span class="sourceLineNo">5160</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5160"></a>
+<span class="sourceLineNo">5161</span>                + "Received a flush prepare marker with a larger seqId: " +<a name="line.5161"></a>
+<span class="sourceLineNo">5162</span>                + flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "<a name="line.5162"></a>
+<span class="sourceLineNo">5163</span>                + prepareFlushResult.flushOpSeqId + ". Ignoring");<a name="line.5163"></a>
+<span class="sourceLineNo">5164</span>            // We do not have multiple active snapshots in the memstore or a way to merge current<a name="line.5164"></a>
+<span class="sourceLineNo">5165</span>            // memstore snapshot with the contents and resnapshot for now. We cannot take<a name="line.5165"></a>
+<span class="sourceLineNo">5166</span>            // another snapshot and drop the previous one because that will cause temporary<a name="line.5166"></a>
+<span class="sourceLineNo">5167</span>            // data loss in the secondary. So we ignore this for now, deferring the resolution<a name="line.5167"></a>
+<span class="sourceLineNo">5168</span>            // to happen when we see the corresponding flush commit marker. If we have a memstore<a name="line.5168"></a>
+<span class="sourceLineNo">5169</span>            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),<a name="line.5169"></a>
+<span class="sourceLineNo">5170</span>            // when we see flush commit for y, we will drop snapshot for x, and can also drop all<a name="line.5170"></a>
+<span class="sourceLineNo">5171</span>            // the memstore edits if everything in memstore is &lt; y. This is the usual case for<a name="line.5171"></a>
+<span class="sourceLineNo">5172</span>            // RS crash + recovery where we might see consequtive prepare flush wal markers.<a name="line.5172"></a>
+<span class="sourceLineNo">5173</span>            // Otherwise, this will cause more memory to be used in secondary replica until a<a name="line.5173"></a>
+<span class="sourceLineNo">5174</span>            // further prapare + commit flush is seen and replayed.<a name="line.5174"></a>
+<span class="sourceLineNo">5175</span>          }<a name="line.5175"></a>
+<span class="sourceLineNo">5176</span>        }<a name="line.5176"></a>
+<span class="sourceLineNo">5177</span>      } finally {<a name="line.5177"></a>
+<span class="sourceLineNo">5178</span>        status.cleanup();<a name="line.5178"></a>
+<span class="sourceLineNo">5179</span>        writestate.notifyAll();<a name="line.5179"></a>
+<span class="sourceLineNo">5180</span>      }<a name="line.5180"></a>
+<span class="sourceLineNo">5181</span>    }<a name="line.5181"></a>
+<span class="sourceLineNo">5182</span>    return null;<a name="line.5182"></a>
+<span class="sourceLineNo">5183</span>  }<a name="line.5183"></a>
+<span class="sourceLineNo">5184</span><a name="line.5184"></a>
+<span class="sourceLineNo">5185</span>  @VisibleForTesting<a name="line.5185"></a>
+<span class="sourceLineNo">5186</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5186"></a>
+<span class="sourceLineNo">5187</span>    justification="Intentional; post memstore flush")<a name="line.5187"></a>
+<span class="sourceLineNo">5188</span>  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {<a name="line.5188"></a>
+<span class="sourceLineNo">5189</span>    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);<a name="line.5189"></a>
+<span class="sourceLineNo">5190</span><a name="line.5190"></a>
+<span class="sourceLineNo">5191</span>    // check whether we have the memstore snapshot with the corresponding seqId. Replay to<a name="line.5191"></a>
+<span class="sourceLineNo">5192</span>    // secondary region replicas are in order, except for when the region moves or then the<a name="line.5192"></a>
+<span class="sourceLineNo">5193</span>    // region server crashes. In those cases, we may receive replay requests out of order from<a name="line.5193"></a>
+<span class="sourceLineNo">5194</span>    // the original seqIds.<a name="line.5194"></a>
+<span class="sourceLineNo">5195</span>    synchronized (writestate) {<a name="line.5195"></a>
+<span class="sourceLineNo">5196</span>      try {<a name="line.5196"></a>
+<span class="sourceLineNo">5197</span>        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {<a name="line.5197"></a>
+<span class="sourceLineNo">5198</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5198"></a>
+<span class="sourceLineNo">5199</span>            + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5199"></a>
+<span class="sourceLineNo">5200</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5200"></a>
+<span class="sourceLineNo">5201</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5201"></a>
+<span class="sourceLineNo">5202</span>          return;<a name="line.5202"></a>
+<span class="sourceLineNo">5203</span>        }<a name="line.5203"></a>
+<span class="sourceLineNo">5204</span><a name="line.5204"></a>
+<span class="sourceLineNo">5205</span>        if (writestate.flushing) {<a name="line.5205"></a>
+<span class="sourceLineNo">5206</span>          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;<a name="line.5206"></a>
+<span class="sourceLineNo">5207</span>          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {<a name="line.5207"></a>
+<span class="sourceLineNo">5208</span>            if (LOG.isDebugEnabled()) {<a name="line.5208"></a>
+<span class="sourceLineNo">5209</span>              LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5209"></a>
+<span class="sourceLineNo">5210</span>                  + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5210"></a>
+<span class="sourceLineNo">5211</span>                  + " and a previous prepared snapshot was found");<a name="line.5211"></a>
+<span class="sourceLineNo">5212</span>            }<a name="line.5212"></a>
+<span class="sourceLineNo">5213</span>            // This is the regular case where we received commit flush after prepare flush<a name="line.5213"></a>
+<span class="sourceLineNo">5214</span>            // corresponding to the same seqId.<a name="line.5214"></a>
+<span class="sourceLineNo">5215</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5215"></a>
+<span class="sourceLineNo">5216</span><a name="line.5216"></a>
+<span class="sourceLineNo">5217</span>            // Set down the memstore size by amount of flush.<a name="line.5217"></a>
+<span class="sourceLineNo">5218</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5218"></a>
+<span class="sourceLineNo">5219</span>            this.prepareFlushResult = null;<a name="line.5219"></a>
+<span class="sourceLineNo">5220</span>            writestate.flushing = false;<a name="line.5220"></a>
+<span class="sourceLineNo">5221</span>          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {<a name="line.5221"></a>
+<span class="sourceLineNo">5222</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5222"></a>
+<span class="sourceLineNo">5223</span>            // we received a flush commit with a smaller seqId than what we have prepared<a name="line.5223"></a>
+<span class="sourceLineNo">5224</span>            // we will pick the flush file up from this commit (if we have not seen it), but we<a name="line.5224"></a>
+<span class="sourceLineNo">5225</span>            // will not drop the memstore<a name="line.5225"></a>
+<span class="sourceLineNo">5226</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5226"></a>
+<span class="sourceLineNo">5227</span>                + "Received a flush commit marker with smaller seqId: "<a name="line.5227"></a>
+<span class="sourceLineNo">5228</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "<a name="line.5228"></a>
+<span class="sourceLineNo">5229</span>                + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"<a name="line.5229"></a>
+<span class="sourceLineNo">5230</span>                +"  prepared memstore snapshot");<a name="line.5230"></a>
+<span class="sourceLineNo">5231</span>            replayFlushInStores(flush, prepareFlushResult, false);<a name="line.5231"></a>
+<span class="sourceLineNo">5232</span><a name="line.5232"></a>
+<span class="sourceLineNo">5233</span>            // snapshot is not dropped, so memstore sizes should not be decremented<a name="line.5233"></a>
+<span class="sourceLineNo">5234</span>            // we still have the prepared snapshot, flushing should still be true<a name="line.5234"></a>
+<span class="sourceLineNo">5235</span>          } else {<a name="line.5235"></a>
+<span class="sourceLineNo">5236</span>            // This should not happen normally. However, lets be safe and guard against these cases<a name="line.5236"></a>
+<span class="sourceLineNo">5237</span>            // we received a flush commit with a larger seqId than what we have prepared<a name="line.5237"></a>
+<span class="sourceLineNo">5238</span>            // we will pick the flush file for this. We will also obtain the updates lock and<a name="line.5238"></a>
+<span class="sourceLineNo">5239</span>            // look for contents of the memstore to see whether we have edits after this seqId.<a name="line.5239"></a>
+<span class="sourceLineNo">5240</span>            // If not, we will drop all the memstore edits and the snapshot as well.<a name="line.5240"></a>
+<span class="sourceLineNo">5241</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5241"></a>
+<span class="sourceLineNo">5242</span>                + "Received a flush commit marker with larger seqId: "<a name="line.5242"></a>
+<span class="sourceLineNo">5243</span>                + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: " +<a name="line.5243"></a>
+<span class="sourceLineNo">5244</span>                prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"<a name="line.5244"></a>
+<span class="sourceLineNo">5245</span>                +" memstore snapshot");<a name="line.5245"></a>
+<span class="sourceLineNo">5246</span><a name="line.5246"></a>
+<span class="sourceLineNo">5247</span>            replayFlushInStores(flush, prepareFlushResult, true);<a name="line.5247"></a>
 <span class="sourceLineNo">5248</span><a name="line.5248"></a>
-<span class="sourceLineNo">5249</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5249"></a>
-<span class="sourceLineNo">5250</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5250"></a>
-<span class="sourceLineNo">5251</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5251"></a>
-<span class="sourceLineNo">5252</span><a name="line.5252"></a>
-<span class="sourceLineNo">5253</span>            this.prepareFlushResult = null;<a name="line.5253"></a>
-<span class="sourceLineNo">5254</span>            writestate.flushing = false;<a name="line.5254"></a>
-<span class="sourceLineNo">5255</span>          }<a name="line.5255"></a>
-<span class="sourceLineNo">5256</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5256"></a>
-<span class="sourceLineNo">5257</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5257"></a>
-<span class="sourceLineNo">5258</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5258"></a>
-<span class="sourceLineNo">5259</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5259"></a>
-<span class="sourceLineNo">5260</span>          // a previous flush we will not enable reads now.<a name="line.5260"></a>
-<span class="sourceLineNo">5261</span>          this.setReadsEnabled(true);<a name="line.5261"></a>
-<span class="sourceLineNo">5262</span>        } else {<a name="line.5262"></a>
-<span class="sourceLineNo">5263</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5263"></a>
-<span class="sourceLineNo">5264</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5264"></a>
-<span class="sourceLineNo">5265</span>              + ", but no previous prepared snapshot was found");<a name="line.5265"></a>
-<span class="sourceLineNo">5266</span>          // There is no corresponding prepare snapshot from before.<a name="line.5266"></a>
-<span class="sourceLineNo">5267</span>          // We will pick up the new flushed file<a name="line.5267"></a>
-<span class="sourceLineNo">5268</span>          replayFlushInStores(flush, null, false);<a name="line.5268"></a>
-<span class="sourceLineNo">5269</span><a name="line.5269"></a>
-<span class="sourceLineNo">5270</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5270"></a>
-<span class="sourceLineNo">5271</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5271"></a>
-<span class="sourceLineNo">5272</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5272"></a>
-<span class="sourceLineNo">5273</span>        }<a name="line.5273"></a>
-<span class="sourceLineNo">5274</span><a name="line.5274"></a>
-<span class="sourceLineNo">5275</span>        status.markComplete("Flush commit successful");<a name="line.5275"></a>
-<span class="sourceLineNo">5276</span><a name="line.5276"></a>
-<span class="sourceLineNo">5277</span>        // Update the last flushed sequence id for region.<a name="line.5277"></a>
-<span class="sourceLineNo">5278</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5278"></a>
+<span class="sourceLineNo">5249</span>            // Set down the memstore size by amount of flush.<a name="line.5249"></a>
+<span class="sourceLineNo">5250</span>            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());<a name="line.5250"></a>
+<span class="sourceLineNo">5251</span><a name="line.5251"></a>
+<span class="sourceLineNo">5252</span>            // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5252"></a>
+<span class="sourceLineNo">5253</span>            // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5253"></a>
+<span class="sourceLineNo">5254</span>            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5254"></a>
+<span class="sourceLineNo">5255</span><a name="line.5255"></a>
+<span class="sourceLineNo">5256</span>            this.prepareFlushResult = null;<a name="line.5256"></a>
+<span class="sourceLineNo">5257</span>            writestate.flushing = false;<a name="line.5257"></a>
+<span class="sourceLineNo">5258</span>          }<a name="line.5258"></a>
+<span class="sourceLineNo">5259</span>          // If we were waiting for observing a flush or region opening event for not showing<a name="line.5259"></a>
+<span class="sourceLineNo">5260</span>          // partial data after a secondary region crash, we can allow reads now. We can only make<a name="line.5260"></a>
+<span class="sourceLineNo">5261</span>          // sure that we are not showing partial data (for example skipping some previous edits)<a name="line.5261"></a>
+<span class="sourceLineNo">5262</span>          // until we observe a full flush start and flush commit. So if we were not able to find<a name="line.5262"></a>
+<span class="sourceLineNo">5263</span>          // a previous flush we will not enable reads now.<a name="line.5263"></a>
+<span class="sourceLineNo">5264</span>          this.setReadsEnabled(true);<a name="line.5264"></a>
+<span class="sourceLineNo">5265</span>        } else {<a name="line.5265"></a>
+<span class="sourceLineNo">5266</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5266"></a>
+<span class="sourceLineNo">5267</span>              + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()<a name="line.5267"></a>
+<span class="sourceLineNo">5268</span>              + ", but no previous prepared snapshot was found");<a name="line.5268"></a>
+<span class="sourceLineNo">5269</span>          // There is no corresponding prepare snapshot from before.<a name="line.5269"></a>
+<span class="sourceLineNo">5270</span>          // We will pick up the new flushed file<a name="line.5270"></a>
+<span class="sourceLineNo">5271</span>          replayFlushInStores(flush, null, false);<a name="line.5271"></a>
+<span class="sourceLineNo">5272</span><a name="line.5272"></a>
+<span class="sourceLineNo">5273</span>          // Inspect the memstore contents to see whether the memstore contains only edits<a name="line.5273"></a>
+<span class="sourceLineNo">5274</span>          // with seqId smaller than the flush seqId. If so, we can discard those edits.<a name="line.5274"></a>
+<span class="sourceLineNo">5275</span>          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);<a name="line.5275"></a>
+<span class="sourceLineNo">5276</span>        }<a name="line.5276"></a>
+<span class="sourceLineNo">5277</span><a name="line.5277"></a>
+<span class="sourceLineNo">5278</span>        status.markComplete("Flush commit successful");<a name="line.5278"></a>
 <span class="sourceLineNo">5279</span><a name="line.5279"></a>
-<span class="sourceLineNo">5280</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5280"></a>
-<span class="sourceLineNo">5281</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5281"></a>
+<span class="sourceLineNo">5280</span>        // Update the last flushed sequence id for region.<a name="line.5280"></a>
+<span class="sourceLineNo">5281</span>        this.maxFlushedSeqId = flush.getFlushSequenceNumber();<a name="line.5281"></a>
 <span class="sourceLineNo">5282</span><a name="line.5282"></a>
-<span class="sourceLineNo">5283</span>      } catch (FileNotFoundException ex) {<a name="line.5283"></a>
-<span class="sourceLineNo">5284</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5284"></a>
-<span class="sourceLineNo">5285</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5285"></a>
-<span class="sourceLineNo">5286</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5286"></a>
-<span class="sourceLineNo">5287</span>      }<a name="line.5287"></a>
-<span class="sourceLineNo">5288</span>      finally {<a name="line.5288"></a>
-<span class="sourceLineNo">5289</span>        status.cleanup();<a name="line.5289"></a>
-<span class="sourceLineNo">5290</span>        writestate.notifyAll();<a name="line.5290"></a>
-<span class="sourceLineNo">5291</span>      }<a name="line.5291"></a>
-<span class="sourceLineNo">5292</span>    }<a name="line.5292"></a>
-<span class="sourceLineNo">5293</span><a name="line.5293"></a>
-<span class="sourceLineNo">5294</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5294"></a>
-<span class="sourceLineNo">5295</span>    // e.g. checkResources().<a name="line.5295"></a>
-<span class="sourceLineNo">5296</span>    synchronized (this) {<a name="line.5296"></a>
-<span class="sourceLineNo">5297</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5297"></a>
-<span class="sourceLineNo">5298</span>    }<a name="line.5298"></a>
-<span class="sourceLineNo">5299</span>  }<a name="line.5299"></a>
-<span class="sourceLineNo">5300</span><a name="line.5300"></a>
-<span class="sourceLineNo">5301</span>  /**<a name="line.5301"></a>
-<span class="sourceLineNo">5302</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5302"></a>
-<span class="sourceLineNo">5303</span>   * memstore snapshots if requested.<a name="line.5303"></a>
-<span class="sourceLineNo">5304</span>   * @param flush<a name="line.5304"></a>
-<span class="sourceLineNo">5305</span>   * @param prepareFlushResult<a name="line.5305"></a>
-<span class="sourceLineNo">5306</span>   * @param dropMemstoreSnapshot<a name="line.5306"></a>
-<span class="sourceLineNo">5307</span>   * @throws IOException<a name="line.5307"></a>
-<span class="sourceLineNo">5308</span>   */<a name="line.5308"></a>
-<span class="sourceLineNo">5309</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5309"></a>
-<span class="sourceLineNo">5310</span>      boolean dropMemstoreSnapshot)<a name="line.5310"></a>
-<span class="sourceLineNo">5311</span>      throws IOException {<a name="line.5311"></a>
-<span class="sourceLineNo">5312</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5312"></a>
-<span class="sourceLineNo">5313</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5313"></a>
-<span class="sourceLineNo">5314</span>      HStore store = getStore(family);<a name="line.5314"></a>
-<span class="sourceLineNo">5315</span>      if (store == null) {<a name="line.5315"></a>
-<span class="sourceLineNo">5316</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5316"></a>
-<span class="sourceLineNo">5317</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5317"></a>
-<span class="sourceLineNo">5318</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5318"></a>
-<span class="sourceLineNo">5319</span>        continue;<a name="line.5319"></a>
-<span class="sourceLineNo">5320</span>      }<a name="line.5320"></a>
-<span class="sourceLineNo">5321</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5321"></a>
-<span class="sourceLineNo">5322</span>      StoreFlushContext ctx = null;<a name="line.5322"></a>
-<span class="sourceLineNo">5323</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5323"></a>
-<span class="sourceLineNo">5324</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5324"></a>
-<span class="sourceLineNo">5325</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5325"></a>
-<span class="sourceLineNo">5326</span>      } else {<a name="line.5326"></a>
-<span class="sourceLineNo">5327</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5327"></a>
-<span class="sourceLineNo">5328</span>        startTime = prepareFlushResult.startTime;<a name="line.5328"></a>
-<span class="sourceLineNo">5329</span>      }<a name="line.5329"></a>
-<span class="sourceLineNo">5330</span><a name="line.5330"></a>
-<span class="sourceLineNo">5331</span>      if (ctx == null) {<a name="line.5331"></a>
-<span class="sourceLineNo">5332</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5332"></a>
-<span class="sourceLineNo">5333</span>            + "Unexpected: flush commit marker received from store "<a name="line.5333"></a>
-<span class="sourceLineNo">5334</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5334"></a>
-<span class="sourceLineNo">5335</span>        continue;<a name="line.5335"></a>
-<span class="sourceLineNo">5336</span>      }<a name="line.5336"></a>
-<span class="sourceLineNo">5337</span><a name="line.5337"></a>
-<span class="sourceLineNo">5338</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5338"></a>
-<span class="sourceLineNo">5339</span><a name="line.5339"></a>
-<span class="sourceLineNo">5340</span>      // Record latest flush time<a name="line.5340"></a>
-<span class="sourceLineNo">5341</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5341"></a>
-<span class="sourceLineNo">5342</span>    }<a name="line.5342"></a>
-<span class="sourceLineNo">5343</span>  }<a name="line.5343"></a>
-<span class="sourceLineNo">5344</span><a name="line.5344"></a>
-<span class="sourceLineNo">5345</span>  /**<a name="line.5345"></a>
-<span class="sourceLineNo">5346</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5346"></a>
-<span class="sourceLineNo">5347</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5347"></a>
-<span class="sourceLineNo">5348</span>   * when replaying recovered.edits while opening region.<a name="line.5348"></a>
-<span class="sourceLineNo">5349</span>   */<a name="line.5349"></a>
-<span class="sourceLineNo">5350</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5350"></a>
-<span class="sourceLineNo">5351</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5351"></a>
-<span class="sourceLineNo">5352</span>    this.updatesLock.writeLock().lock();<a name="line.5352"></a>
-<span class="sourceLineNo">5353</span>    try {<a name="line.5353"></a>
-<span class="sourceLineNo">5354</span>      for (HStore s : stores.values()) {<a name="line.5354"></a>
-<span class="sourceLineNo">5355</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5355"></a>
-<span class="sourceLineNo">5356</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5356"></a>
-<span class="sourceLineNo">5357</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5357"></a>
-<span class="sourceLineNo">5358</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5358"></a>
-<span class="sourceLineNo">5359</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5359"></a>
-<span class="sourceLineNo">5360</span>      }<a name="line.5360"></a>
-<span class="sourceLineNo">5361</span>      return totalFreedSize.getMemStoreSize();<a name="line.5361"></a>
-<span class="sourceLineNo">5362</span>    } finally {<a name="line.5362"></a>
-<span class="sourceLineNo">5363</span>      this.updatesLock.writeLock().unlock();<a name="line.5363"></a>
-<span class="sourceLineNo">5364</span>    }<a name="line.5364"></a>
-<span class="sourceLineNo">5365</span>  }<a name="line.5365"></a>
-<span class="sourceLineNo">5366</span><a name="line.5366"></a>
-<span class="sourceLineNo">5367</span>  /**<a name="line.5367"></a>
-<span class="sourceLineNo">5368</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5368"></a>
-<span class="sourceLineNo">5369</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5369"></a>
-<span class="sourceLineNo">5370</span>   * @throws IOException<a name="line.5370"></a>
-<span class="sourceLineNo">5371</span>   */<a name="line.5371"></a>
-<span class="sourceLineNo">5372</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5372"></a>
-<span class="sourceLineNo">5373</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5373"></a>
-<span class="sourceLineNo">5374</span>    this.updatesLock.writeLock().lock();<a name="line.5374"></a>
-<span class="sourceLineNo">5375</span>    try {<a name="line.5375"></a>
-<span class="sourceLineNo">5376</span><a name="line.5376"></a>
-<span class="sourceLineNo">5377</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5377"></a>
-<span class="sourceLineNo">5378</span>      if (seqId &gt;= currentSeqId) {<a name="line.5378"></a>
-<span class="sourceLineNo">5379</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5379"></a>
-<span class="sourceLineNo">5380</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5380"></a>
-<span class="sourceLineNo">5381</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5381"></a>
-<span class="sourceLineNo">5382</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5382"></a>
-<span class="sourceLineNo">5383</span><a name="line.5383"></a>
-<span class="sourceLineNo">5384</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5384"></a>
-<span class="sourceLineNo">5385</span>        if (store == null) {<a name="line.5385"></a>
-<span class="sourceLineNo">5386</span>          for (HStore s : stores.values()) {<a name="line.5386"></a>
-<span class="sourceLineNo">5387</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5387"></a>
-<span class="sourceLineNo">5388</span>          }<a name="line.5388"></a>
-<span class="sourceLineNo">5389</span>        } else {<a name="line.5389"></a>
-<span class="sourceLineNo">5390</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5390"></a>
-<span class="sourceLineNo">5391</span>        }<a name="line.5391"></a>
-<span class="sourceLineNo">5392</span>      } else {<a name="line.5392"></a>
-<span class="sourceLineNo">5393</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5393"></a>
-<span class="sourceLineNo">5394</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5394"></a>
-<span class="sourceLineNo">5395</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5395"></a>
-<span class="sourceLineNo">5396</span>      }<a name="line.5396"></a>
-<span class="sourceLineNo">5397</span>    } finally {<a name="line.5397"></a>
-<span class="sourceLineNo">5398</span>      this.updatesLock.writeLock().unlock();<a name="line.5398"></a>
-<span class="sourceLineNo">5399</span>    }<a name="line.5399"></a>
-<span class="sourceLineNo">5400</span>    return totalFreedSize.getMemStoreSize();<a name="line.5400"></a>
-<span class="sourceLineNo">5401</span>  }<a name="line.5401"></a>
-<span class="sourceLineNo">5402</span><a name="line.5402"></a>
-<span class="sourceLineNo">5403</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5403"></a>
-<span class="sourceLineNo">5404</span>      throws IOException {<a name="line.5404"></a>
-<span class="sourceLineNo">5405</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5405"></a>
-<span class="sourceLineNo">5406</span>    this.decrMemStoreSize(flushableSize);<a name="line.5406"></a>
-<span class="sourceLineNo">5407</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5407"></a>
-<span class="sourceLineNo">5408</span>    ctx.prepare();<a name="line.5408"></a>
-<span class="sourceLineNo">5409</span>    ctx.abort();<a name="line.5409"></a>
-<span class="sourceLineNo">5410</span>    return flushableSize;<a name="line.5410"></a>
-<span class="sourceLineNo">5411</span>  }<a name="line.5411"></a>
-<span class="sourceLineNo">5412</span><a name="line.5412"></a>
-<span class="sourceLineNo">5413</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5413"></a>
-<span class="sourceLineNo">5414</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5414"></a>
-<span class="sourceLineNo">5415</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5415"></a>
-<span class="sourceLineNo">5416</span>    // that will drop the snapshot<a name="line.5416"></a>
-<span class="sourceLineNo">5417</span>  }<a name="line.5417"></a>
-<span class="sourceLineNo">5418</span><a name="line.5418"></a>
-<span class="sourceLineNo">5419</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5419"></a>
-<span class="sourceLineNo">5420</span>    synchronized (writestate) {<a name="line.5420"></a>
-<span class="sourceLineNo">5421</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5421"></a>
-<span class="sourceLineNo">5422</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5422"></a>
-<span class="sourceLineNo">5423</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5423"></a>
-<span class="sourceLineNo">5424</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5424"></a>
-<span class="sourceLineNo">5425</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5425"></a>
-<span class="sourceLineNo">5426</span>        return;<a name="line.5426"></a>
-<span class="sourceLineNo">5427</span>      }<a name="line.5427"></a>
-<span class="sourceLineNo">5428</span><a name="line.5428"></a>
-<span class="sourceLineNo">5429</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5429"></a>
-<span class="sourceLineNo">5430</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5430"></a>
-<span class="sourceLineNo">5431</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5431"></a>
-<span class="sourceLineNo">5432</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5432"></a>
-<span class="sourceLineNo">5433</span>      // assignment.<a name="line.5433"></a>
-<span class="sourceLineNo">5434</span>      this.setReadsEnabled(true);<a name="line.5434"></a>
-<span class="sourceLineNo">5435</span>    }<a name="line.5435"></a>
-<span class="sourceLineNo">5436</span>  }<a name="line.5436"></a>
-<span class="sourceLineNo">5437</span><a name="line.5437"></a>
-<span class="sourceLineNo">5438</span>  @VisibleForTesting<a name="line.5438"></a>
-<span class="sourceLineNo">5439</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5439"></a>
-<span class="sourceLineNo">5440</span>    return prepareFlushResult;<a name="line.5440"></a>
-<span class="sourceLineNo">5441</span>  }<a name="line.5441"></a>
-<span class="sourceLineNo">5442</span><a name="line.5442"></a>
-<span class="sourceLineNo">5443</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5443"></a>
-<span class="sourceLineNo">5444</span>      justification="Intentional; cleared the memstore")<a name="line.5444"></a>
-<span class="sourceLineNo">5445</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5445"></a>
-<span class="sourceLineNo">5446</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5446"></a>
-<span class="sourceLineNo">5447</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5447"></a>
-<span class="sourceLineNo">5448</span><a name="line.5448"></a>
-<span class="sourceLineNo">5449</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5449"></a>
-<span class="sourceLineNo">5450</span>    try {<a name="line.5450"></a>
-<span class="sourceLineNo">5451</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5451"></a>
-<span class="sourceLineNo">5452</span>        return; // if primary nothing to do<a name="line.5452"></a>
-<span class="sourceLineNo">5453</span>      }<a name="line.5453"></a>
-<span class="sourceLineNo">5454</span><a name="line.5454"></a>
-<span class="sourceLineNo">5455</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5455"></a>
-<span class="sourceLineNo">5456</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5456"></a>
-<span class="sourceLineNo">5457</span>        return;<a name="line.5457"></a>
-<span class="sourceLineNo">5458</span>      }<a name="line.5458"></a>
-<span class="sourceLineNo">5459</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5459"></a>
-<span class="sourceLineNo">5460</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5460"></a>
-<span class="sourceLineNo">5461</span>            + "Unknown region event received, ignoring :"<a name="line.5461"></a>
-<span class="sourceLineNo">5462</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5462"></a>
-<span class="sourceLineNo">5463</span>        return;<a name="line.5463"></a>
-<span class="sourceLineNo">5464</span>      }<a name="line.5464"></a>
-<span class="sourceLineNo">5465</span><a name="line.5465"></a>
-<span class="sourceLineNo">5466</span>      if (LOG.isDebugEnabled()) {<a name="line.5466"></a>
-<span class="sourceLineNo">5467</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5467"></a>
-<span class="sourceLineNo">5468</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5468"></a>
-<span class="sourceLineNo">5469</span>      }<a name="line.5469"></a>
-<span class="sourceLineNo">5470</span><a name="line.5470"></a>
-<span class="sourceLineNo">5471</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5471"></a>
-<span class="sourceLineNo">5472</span>      synchronized (writestate) {<a name="line.5472"></a>
-<span class="sourceLineNo">5473</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5473"></a>
-<span class="sourceLineNo">5474</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5474"></a>
-<span class="sourceLineNo">5475</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5475"></a>
-<span class="sourceLineNo">5476</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5476"></a>
-<span class="sourceLineNo">5477</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5477"></a>
-<span class="sourceLineNo">5478</span>        // smaller than this seqId<a name="line.5478"></a>
-<span class="sourceLineNo">5479</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5479"></a>
-<span class="sourceLineNo">5480</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5480"></a>
-<span class="sourceLineNo">5481</span>        } else {<a name="line.5481"></a>
-<span class="sourceLineNo">5482</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5482"></a>
-<span class="sourceLineNo">5483</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5483"></a>
-<span class="sourceLineNo">5484</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5484"></a>
-<span class="sourceLineNo">5485</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5485"></a>
-<span class="sourceLineNo">5486</span>          return;<a name="line.5486"></a>
-<span class="sourceLineNo">5487</span>        }<a name="line.5487"></a>
-<span class="sourceLineNo">5488</span><a name="line.5488"></a>
-<span class="sourceLineNo">5489</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5489"></a>
-<span class="sourceLineNo">5490</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5490"></a>
-<span class="sourceLineNo">5491</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5491"></a>
-<span class="sourceLineNo">5492</span>          // stores of primary may be different now<a name="line.5492"></a>
-<span class="sourceLineNo">5493</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5493"></a>
-<span class="sourceLineNo">5494</span>          HStore store = getStore(family);<a name="line.5494"></a>
-<span class="sourceLineNo">5495</span>          if (store == null) {<a name="line.5495"></a>
-<span class="sourceLineNo">5496</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5496"></a>
-<span class="sourceLineNo">5497</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5497"></a>
-<span class="sourceLineNo">5498</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5498"></a>
-<span class="sourceLineNo">5499</span>            continue;<a name="line.5499"></a>
-<span class="sourceLineNo">5500</span>          }<a name="line.5500"></a>
-<span class="sourceLineNo">5501</span><a name="line.5501"></a>
-<span class="sourceLineNo">5502</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5502"></a>
-<span class="sourceLineNo">5503</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5503"></a>
-<span class="sourceLineNo">5504</span>          try {<a name="line.5504"></a>
-<span class="sourceLineNo">5505</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5505"></a>
-<span class="sourceLineNo">5506</span>          } catch (FileNotFoundException ex) {<a name="line.5506"></a>
-<span class="sourceLineNo">5507</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5507"></a>
-<span class="sourceLineNo">5508</span>                    + "At least one of the store files: " + storeFiles<a name="line.5508"></a>
-<span class="sourceLineNo">5509</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5509"></a>
-<span class="sourceLineNo">5510</span>            continue;<a name="line.5510"></a>
-<span class="sourceLineNo">5511</span>          }<a name="line.5511"></a>
-<span class="sourceLineNo">5512</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5512"></a>
-<span class="sourceLineNo">5513</span>            // Record latest flush time if we picked up new files<a name="line.5513"></a>
-<span class="sourceLineNo">5514</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5514"></a>
-<span class="sourceLineNo">5515</span>          }<a name="line.5515"></a>
-<span class="sourceLineNo">5516</span><a name="line.5516"></a>
-<span class="sourceLineNo">5517</span>          if (writestate.flushing) {<a name="line.5517"></a>
-<span class="sourceLineNo">5518</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5518"></a>
-<span class="sourceLineNo">5519</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5519"></a>
-<span class="sourceLineNo">5520</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5520"></a>
-<span class="sourceLineNo">5521</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5521"></a>
-<span class="sourceLineNo">5522</span>              if (ctx != null) {<a name="line.5522"></a>
-<span class="sourceLineNo">5523</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5523"></a>
-<span class="sourceLineNo">5524</span>                ctx.abort();<a name="line.5524"></a>
-<span class="sourceLineNo">5525</span>                this.decrMemStoreSize(mss);<a name="line.5525"></a>
-<span class="sourceLineNo">5526</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5526"></a>
-<span class="sourceLineNo">5527</span>              }<a name="line.5527"></a>
-<span class="sourceLineNo">5528</span>            }<a name="line.5528"></a>
-<span class="sourceLineNo">5529</span>          }<a name="line.5529"></a>
-<span class="sourceLineNo">5530</span><a name="line.5530"></a>
-<span class="sourceLineNo">5531</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5531"></a>
-<span class="sourceLineNo">5532</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5532"></a>
-<span class="sourceLineNo">5533</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5533"></a>
-<span class="sourceLineNo">5534</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5534"></a>
-<span class="sourceLineNo">5535</span>          }<a name="line.5535"></a>
-<span class="sourceLineNo">5536</span>        }<a name="line.5536"></a>
-<span class="sourceLineNo">5537</span><a name="line.5537"></a>
-<span class="sourceLineNo">5538</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5538"></a>
-<span class="sourceLineNo">5539</span>        // prepareFlushResult<a name="line.5539"></a>
-<span class="sourceLineNo">5540</span>        dropPrepareFlushIfPossible();<a name="line.5540"></a>
-<span class="sourceLineNo">5541</span><a name="line.5541"></a>
-<span class="sourceLineNo">5542</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5542"></a>
-<span class="sourceLineNo">5543</span>        mvcc.await();<a name="line.5543"></a>
+<span class="sourceLineNo">5283</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5283"></a>
+<span class="sourceLineNo">5284</span>        mvcc.advanceTo(flush.getFlushSequenceNumber());<a name="line.5284"></a>
+<span class="sourceLineNo">5285</span><a name="line.5285"></a>
+<span class="sourceLineNo">5286</span>      } catch (FileNotFoundException ex) {<a name="line.5286"></a>
+<span class="sourceLineNo">5287</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5287"></a>
+<span class="sourceLineNo">5288</span>            + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)<a name="line.5288"></a>
+<span class="sourceLineNo">5289</span>            + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5289"></a>
+<span class="sourceLineNo">5290</span>      }<a name="line.5290"></a>
+<span class="sourceLineNo">5291</span>      finally {<a name="line.5291"></a>
+<span class="sourceLineNo">5292</span>        status.cleanup();<a name="line.5292"></a>
+<span class="sourceLineNo">5293</span>        writestate.notifyAll();<a name="line.5293"></a>
+<span class="sourceLineNo">5294</span>      }<a name="line.5294"></a>
+<span class="sourceLineNo">5295</span>    }<a name="line.5295"></a>
+<span class="sourceLineNo">5296</span><a name="line.5296"></a>
+<span class="sourceLineNo">5297</span>    // C. Finally notify anyone waiting on memstore to clear:<a name="line.5297"></a>
+<span class="sourceLineNo">5298</span>    // e.g. checkResources().<a name="line.5298"></a>
+<span class="sourceLineNo">5299</span>    synchronized (this) {<a name="line.5299"></a>
+<span class="sourceLineNo">5300</span>      notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5300"></a>
+<span class="sourceLineNo">5301</span>    }<a name="line.5301"></a>
+<span class="sourceLineNo">5302</span>  }<a name="line.5302"></a>
+<span class="sourceLineNo">5303</span><a name="line.5303"></a>
+<span class="sourceLineNo">5304</span>  /**<a name="line.5304"></a>
+<span class="sourceLineNo">5305</span>   * Replays the given flush descriptor by opening the flush files in stores and dropping the<a name="line.5305"></a>
+<span class="sourceLineNo">5306</span>   * memstore snapshots if requested.<a name="line.5306"></a>
+<span class="sourceLineNo">5307</span>   * @param flush<a name="line.5307"></a>
+<span class="sourceLineNo">5308</span>   * @param prepareFlushResult<a name="line.5308"></a>
+<span class="sourceLineNo">5309</span>   * @param dropMemstoreSnapshot<a name="line.5309"></a>
+<span class="sourceLineNo">5310</span>   * @throws IOException<a name="line.5310"></a>
+<span class="sourceLineNo">5311</span>   */<a name="line.5311"></a>
+<span class="sourceLineNo">5312</span>  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,<a name="line.5312"></a>
+<span class="sourceLineNo">5313</span>      boolean dropMemstoreSnapshot)<a name="line.5313"></a>
+<span class="sourceLineNo">5314</span>      throws IOException {<a name="line.5314"></a>
+<span class="sourceLineNo">5315</span>    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {<a name="line.5315"></a>
+<span class="sourceLineNo">5316</span>      byte[] family = storeFlush.getFamilyName().toByteArray();<a name="line.5316"></a>
+<span class="sourceLineNo">5317</span>      HStore store = getStore(family);<a name="line.5317"></a>
+<span class="sourceLineNo">5318</span>      if (store == null) {<a name="line.5318"></a>
+<span class="sourceLineNo">5319</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5319"></a>
+<span class="sourceLineNo">5320</span>            + "Received a flush commit marker from primary, but the family is not found."<a name="line.5320"></a>
+<span class="sourceLineNo">5321</span>            + "Ignoring StoreFlushDescriptor:" + storeFlush);<a name="line.5321"></a>
+<span class="sourceLineNo">5322</span>        continue;<a name="line.5322"></a>
+<span class="sourceLineNo">5323</span>      }<a name="line.5323"></a>
+<span class="sourceLineNo">5324</span>      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();<a name="line.5324"></a>
+<span class="sourceLineNo">5325</span>      StoreFlushContext ctx = null;<a name="line.5325"></a>
+<span class="sourceLineNo">5326</span>      long startTime = EnvironmentEdgeManager.currentTime();<a name="line.5326"></a>
+<span class="sourceLineNo">5327</span>      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {<a name="line.5327"></a>
+<span class="sourceLineNo">5328</span>        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);<a name="line.5328"></a>
+<span class="sourceLineNo">5329</span>      } else {<a name="line.5329"></a>
+<span class="sourceLineNo">5330</span>        ctx = prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5330"></a>
+<span class="sourceLineNo">5331</span>        startTime = prepareFlushResult.startTime;<a name="line.5331"></a>
+<span class="sourceLineNo">5332</span>      }<a name="line.5332"></a>
+<span class="sourceLineNo">5333</span><a name="line.5333"></a>
+<span class="sourceLineNo">5334</span>      if (ctx == null) {<a name="line.5334"></a>
+<span class="sourceLineNo">5335</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5335"></a>
+<span class="sourceLineNo">5336</span>            + "Unexpected: flush commit marker received from store "<a name="line.5336"></a>
+<span class="sourceLineNo">5337</span>            + Bytes.toString(family) + " but no associated flush context. Ignoring");<a name="line.5337"></a>
+<span class="sourceLineNo">5338</span>        continue;<a name="line.5338"></a>
+<span class="sourceLineNo">5339</span>      }<a name="line.5339"></a>
+<span class="sourceLineNo">5340</span><a name="line.5340"></a>
+<span class="sourceLineNo">5341</span>      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush<a name="line.5341"></a>
+<span class="sourceLineNo">5342</span><a name="line.5342"></a>
+<span class="sourceLineNo">5343</span>      // Record latest flush time<a name="line.5343"></a>
+<span class="sourceLineNo">5344</span>      this.lastStoreFlushTimeMap.put(store, startTime);<a name="line.5344"></a>
+<span class="sourceLineNo">5345</span>    }<a name="line.5345"></a>
+<span class="sourceLineNo">5346</span>  }<a name="line.5346"></a>
+<span class="sourceLineNo">5347</span><a name="line.5347"></a>
+<span class="sourceLineNo">5348</span>  /**<a name="line.5348"></a>
+<span class="sourceLineNo">5349</span>   * Be careful, this method will drop all data in the memstore of this region.<a name="line.5349"></a>
+<span class="sourceLineNo">5350</span>   * Currently, this method is used to drop memstore to prevent memory leak<a name="line.5350"></a>
+<span class="sourceLineNo">5351</span>   * when replaying recovered.edits while opening region.<a name="line.5351"></a>
+<span class="sourceLineNo">5352</span>   */<a name="line.5352"></a>
+<span class="sourceLineNo">5353</span>  public MemStoreSize dropMemStoreContents() throws IOException {<a name="line.5353"></a>
+<span class="sourceLineNo">5354</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5354"></a>
+<span class="sourceLineNo">5355</span>    this.updatesLock.writeLock().lock();<a name="line.5355"></a>
+<span class="sourceLineNo">5356</span>    try {<a name="line.5356"></a>
+<span class="sourceLineNo">5357</span>      for (HStore s : stores.values()) {<a name="line.5357"></a>
+<span class="sourceLineNo">5358</span>        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);<a name="line.5358"></a>
+<span class="sourceLineNo">5359</span>        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "<a name="line.5359"></a>
+<span class="sourceLineNo">5360</span>                + this.getRegionInfo().getRegionNameAsString()<a name="line.5360"></a>
+<span class="sourceLineNo">5361</span>                + " , dropped memstoresize: [" + memStoreSize + " }");<a name="line.5361"></a>
+<span class="sourceLineNo">5362</span>        totalFreedSize.incMemStoreSize(memStoreSize);<a name="line.5362"></a>
+<span class="sourceLineNo">5363</span>      }<a name="line.5363"></a>
+<span class="sourceLineNo">5364</span>      return totalFreedSize.getMemStoreSize();<a name="line.5364"></a>
+<span class="sourceLineNo">5365</span>    } finally {<a name="line.5365"></a>
+<span class="sourceLineNo">5366</span>      this.updatesLock.writeLock().unlock();<a name="line.5366"></a>
+<span class="sourceLineNo">5367</span>    }<a name="line.5367"></a>
+<span class="sourceLineNo">5368</span>  }<a name="line.5368"></a>
+<span class="sourceLineNo">5369</span><a name="line.5369"></a>
+<span class="sourceLineNo">5370</span>  /**<a name="line.5370"></a>
+<span class="sourceLineNo">5371</span>   * Drops the memstore contents after replaying a flush descriptor or region open event replay<a name="line.5371"></a>
+<span class="sourceLineNo">5372</span>   * if the memstore edits have seqNums smaller than the given seq id<a name="line.5372"></a>
+<span class="sourceLineNo">5373</span>   * @throws IOException<a name="line.5373"></a>
+<span class="sourceLineNo">5374</span>   */<a name="line.5374"></a>
+<span class="sourceLineNo">5375</span>  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {<a name="line.5375"></a>
+<span class="sourceLineNo">5376</span>    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();<a name="line.5376"></a>
+<span class="sourceLineNo">5377</span>    this.updatesLock.writeLock().lock();<a name="line.5377"></a>
+<span class="sourceLineNo">5378</span>    try {<a name="line.5378"></a>
+<span class="sourceLineNo">5379</span><a name="line.5379"></a>
+<span class="sourceLineNo">5380</span>      long currentSeqId = mvcc.getReadPoint();<a name="line.5380"></a>
+<span class="sourceLineNo">5381</span>      if (seqId &gt;= currentSeqId) {<a name="line.5381"></a>
+<span class="sourceLineNo">5382</span>        // then we can drop the memstore contents since everything is below this seqId<a name="line.5382"></a>
+<span class="sourceLineNo">5383</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5383"></a>
+<span class="sourceLineNo">5384</span>            + "Dropping memstore contents as well since replayed flush seqId: "<a name="line.5384"></a>
+<span class="sourceLineNo">5385</span>            + seqId + " is greater than current seqId:" + currentSeqId);<a name="line.5385"></a>
+<span class="sourceLineNo">5386</span><a name="line.5386"></a>
+<span class="sourceLineNo">5387</span>        // Prepare flush (take a snapshot) and then abort (drop the snapshot)<a name="line.5387"></a>
+<span class="sourceLineNo">5388</span>        if (store == null) {<a name="line.5388"></a>
+<span class="sourceLineNo">5389</span>          for (HStore s : stores.values()) {<a name="line.5389"></a>
+<span class="sourceLineNo">5390</span>            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));<a name="line.5390"></a>
+<span class="sourceLineNo">5391</span>          }<a name="line.5391"></a>
+<span class="sourceLineNo">5392</span>        } else {<a name="line.5392"></a>
+<span class="sourceLineNo">5393</span>          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));<a name="line.5393"></a>
+<span class="sourceLineNo">5394</span>        }<a name="line.5394"></a>
+<span class="sourceLineNo">5395</span>      } else {<a name="line.5395"></a>
+<span class="sourceLineNo">5396</span>        LOG.info(getRegionInfo().getEncodedName() + " : "<a name="line.5396"></a>
+<span class="sourceLineNo">5397</span>            + "Not dropping memstore contents since replayed flush seqId: "<a name="line.5397"></a>
+<span class="sourceLineNo">5398</span>            + seqId + " is smaller than current seqId:" + currentSeqId);<a name="line.5398"></a>
+<span class="sourceLineNo">5399</span>      }<a name="line.5399"></a>
+<span class="sourceLineNo">5400</span>    } finally {<a name="line.5400"></a>
+<span class="sourceLineNo">5401</span>      this.updatesLock.writeLock().unlock();<a name="line.5401"></a>
+<span class="sourceLineNo">5402</span>    }<a name="line.5402"></a>
+<span class="sourceLineNo">5403</span>    return totalFreedSize.getMemStoreSize();<a name="line.5403"></a>
+<span class="sourceLineNo">5404</span>  }<a name="line.5404"></a>
+<span class="sourceLineNo">5405</span><a name="line.5405"></a>
+<span class="sourceLineNo">5406</span>  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)<a name="line.5406"></a>
+<span class="sourceLineNo">5407</span>      throws IOException {<a name="line.5407"></a>
+<span class="sourceLineNo">5408</span>    MemStoreSize flushableSize = s.getFlushableSize();<a name="line.5408"></a>
+<span class="sourceLineNo">5409</span>    this.decrMemStoreSize(flushableSize);<a name="line.5409"></a>
+<span class="sourceLineNo">5410</span>    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);<a name="line.5410"></a>
+<span class="sourceLineNo">5411</span>    ctx.prepare();<a name="line.5411"></a>
+<span class="sourceLineNo">5412</span>    ctx.abort();<a name="line.5412"></a>
+<span class="sourceLineNo">5413</span>    return flushableSize;<a name="line.5413"></a>
+<span class="sourceLineNo">5414</span>  }<a name="line.5414"></a>
+<span class="sourceLineNo">5415</span><a name="line.5415"></a>
+<span class="sourceLineNo">5416</span>  private void replayWALFlushAbortMarker(FlushDescriptor flush) {<a name="line.5416"></a>
+<span class="sourceLineNo">5417</span>    // nothing to do for now. A flush abort will cause a RS abort which means that the region<a name="line.5417"></a>
+<span class="sourceLineNo">5418</span>    // will be opened somewhere else later. We will see the region open event soon, and replaying<a name="line.5418"></a>
+<span class="sourceLineNo">5419</span>    // that will drop the snapshot<a name="line.5419"></a>
+<span class="sourceLineNo">5420</span>  }<a name="line.5420"></a>
+<span class="sourceLineNo">5421</span><a name="line.5421"></a>
+<span class="sourceLineNo">5422</span>  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {<a name="line.5422"></a>
+<span class="sourceLineNo">5423</span>    synchronized (writestate) {<a name="line.5423"></a>
+<span class="sourceLineNo">5424</span>      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {<a name="line.5424"></a>
+<span class="sourceLineNo">5425</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5425"></a>
+<span class="sourceLineNo">5426</span>          + "Skipping replaying flush event :" + TextFormat.shortDebugString(flush)<a name="line.5426"></a>
+<span class="sourceLineNo">5427</span>          + " because its sequence id " + replaySeqId + " is smaller than this regions "<a name="line.5427"></a>
+<span class="sourceLineNo">5428</span>          + "lastReplayedOpenRegionSeqId of " + lastReplayedOpenRegionSeqId);<a name="line.5428"></a>
+<span class="sourceLineNo">5429</span>        return;<a name="line.5429"></a>
+<span class="sourceLineNo">5430</span>      }<a name="line.5430"></a>
+<span class="sourceLineNo">5431</span><a name="line.5431"></a>
+<span class="sourceLineNo">5432</span>      // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5432"></a>
+<span class="sourceLineNo">5433</span>      // data after a secondary region crash, we can allow reads now. This event means that the<a name="line.5433"></a>
+<span class="sourceLineNo">5434</span>      // primary was not able to flush because memstore is empty when we requested flush. By the<a name="line.5434"></a>
+<span class="sourceLineNo">5435</span>      // time we observe this, we are guaranteed to have up to date seqId with our previous<a name="line.5435"></a>
+<span class="sourceLineNo">5436</span>      // assignment.<a name="line.5436"></a>
+<span class="sourceLineNo">5437</span>      this.setReadsEnabled(true);<a name="line.5437"></a>
+<span class="sourceLineNo">5438</span>    }<a name="line.5438"></a>
+<span class="sourceLineNo">5439</span>  }<a name="line.5439"></a>
+<span class="sourceLineNo">5440</span><a name="line.5440"></a>
+<span class="sourceLineNo">5441</span>  @VisibleForTesting<a name="line.5441"></a>
+<span class="sourceLineNo">5442</span>  PrepareFlushResult getPrepareFlushResult() {<a name="line.5442"></a>
+<span class="sourceLineNo">5443</span>    return prepareFlushResult;<a name="line.5443"></a>
+<span class="sourceLineNo">5444</span>  }<a name="line.5444"></a>
+<span class="sourceLineNo">5445</span><a name="line.5445"></a>
+<span class="sourceLineNo">5446</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",<a name="line.5446"></a>
+<span class="sourceLineNo">5447</span>      justification="Intentional; cleared the memstore")<a name="line.5447"></a>
+<span class="sourceLineNo">5448</span>  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {<a name="line.5448"></a>
+<span class="sourceLineNo">5449</span>    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),<a name="line.5449"></a>
+<span class="sourceLineNo">5450</span>      "RegionEvent marker from WAL ", regionEvent);<a name="line.5450"></a>
+<span class="sourceLineNo">5451</span><a name="line.5451"></a>
+<span class="sourceLineNo">5452</span>    startRegionOperation(Operation.REPLAY_EVENT);<a name="line.5452"></a>
+<span class="sourceLineNo">5453</span>    try {<a name="line.5453"></a>
+<span class="sourceLineNo">5454</span>      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5454"></a>
+<span class="sourceLineNo">5455</span>        return; // if primary nothing to do<a name="line.5455"></a>
+<span class="sourceLineNo">5456</span>      }<a name="line.5456"></a>
+<span class="sourceLineNo">5457</span><a name="line.5457"></a>
+<span class="sourceLineNo">5458</span>      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {<a name="line.5458"></a>
+<span class="sourceLineNo">5459</span>        // nothing to do on REGION_CLOSE for now.<a name="line.5459"></a>
+<span class="sourceLineNo">5460</span>        return;<a name="line.5460"></a>
+<span class="sourceLineNo">5461</span>      }<a name="line.5461"></a>
+<span class="sourceLineNo">5462</span>      if (regionEvent.getEventType() != EventType.REGION_OPEN) {<a name="line.5462"></a>
+<span class="sourceLineNo">5463</span>        LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5463"></a>
+<span class="sourceLineNo">5464</span>            + "Unknown region event received, ignoring :"<a name="line.5464"></a>
+<span class="sourceLineNo">5465</span>            + TextFormat.shortDebugString(regionEvent));<a name="line.5465"></a>
+<span class="sourceLineNo">5466</span>        return;<a name="line.5466"></a>
+<span class="sourceLineNo">5467</span>      }<a name="line.5467"></a>
+<span class="sourceLineNo">5468</span><a name="line.5468"></a>
+<span class="sourceLineNo">5469</span>      if (LOG.isDebugEnabled()) {<a name="line.5469"></a>
+<span class="sourceLineNo">5470</span>        LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5470"></a>
+<span class="sourceLineNo">5471</span>          + "Replaying region open event marker " + TextFormat.shortDebugString(regionEvent));<a name="line.5471"></a>
+<span class="sourceLineNo">5472</span>      }<a name="line.5472"></a>
+<span class="sourceLineNo">5473</span><a name="line.5473"></a>
+<span class="sourceLineNo">5474</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5474"></a>
+<span class="sourceLineNo">5475</span>      synchronized (writestate) {<a name="line.5475"></a>
+<span class="sourceLineNo">5476</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5476"></a>
+<span class="sourceLineNo">5477</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5477"></a>
+<span class="sourceLineNo">5478</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5478"></a>
+<span class="sourceLineNo">5479</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5479"></a>
+<span class="sourceLineNo">5480</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5480"></a>
+<span class="sourceLineNo">5481</span>        // smaller than this seqId<a name="line.5481"></a>
+<span class="sourceLineNo">5482</span>        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5482"></a>
+<span class="sourceLineNo">5483</span>          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();<a name="line.5483"></a>
+<span class="sourceLineNo">5484</span>        } else {<a name="line.5484"></a>
+<span class="sourceLineNo">5485</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5485"></a>
+<span class="sourceLineNo">5486</span>            + "Skipping replaying region event :" + TextFormat.shortDebugString(regionEvent)<a name="line.5486"></a>
+<span class="sourceLineNo">5487</span>            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "<a name="line.5487"></a>
+<span class="sourceLineNo">5488</span>            + " of " + lastReplayedOpenRegionSeqId);<a name="line.5488"></a>
+<span class="sourceLineNo">5489</span>          return;<a name="line.5489"></a>
+<span class="sourceLineNo">5490</span>        }<a name="line.5490"></a>
+<span class="sourceLineNo">5491</span><a name="line.5491"></a>
+<span class="sourceLineNo">5492</span>        // region open lists all the files that the region has at the time of the opening. Just pick<a name="line.5492"></a>
+<span class="sourceLineNo">5493</span>        // all the files and drop prepared flushes and empty memstores<a name="line.5493"></a>
+<span class="sourceLineNo">5494</span>        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {<a name="line.5494"></a>
+<span class="sourceLineNo">5495</span>          // stores of primary may be different now<a name="line.5495"></a>
+<span class="sourceLineNo">5496</span>          byte[] family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5496"></a>
+<span class="sourceLineNo">5497</span>          HStore store = getStore(family);<a name="line.5497"></a>
+<span class="sourceLineNo">5498</span>          if (store == null) {<a name="line.5498"></a>
+<span class="sourceLineNo">5499</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5499"></a>
+<span class="sourceLineNo">5500</span>                + "Received a region open marker from primary, but the family is not found. "<a name="line.5500"></a>
+<span class="sourceLineNo">5501</span>                + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5501"></a>
+<span class="sourceLineNo">5502</span>            continue;<a name="line.5502"></a>
+<span class="sourceLineNo">5503</span>          }<a name="line.5503"></a>
+<span class="sourceLineNo">5504</span><a name="line.5504"></a>
+<span class="sourceLineNo">5505</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5505"></a>
+<span class="sourceLineNo">5506</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5506"></a>
+<span class="sourceLineNo">5507</span>          try {<a name="line.5507"></a>
+<span class="sourceLineNo">5508</span>            store.refreshStoreFiles(storeFiles); // replace the files with the new ones<a name="line.5508"></a>
+<span class="sourceLineNo">5509</span>          } catch (FileNotFoundException ex) {<a name="line.5509"></a>
+<span class="sourceLineNo">5510</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5510"></a>
+<span class="sourceLineNo">5511</span>                    + "At least one of the store files: " + storeFiles<a name="line.5511"></a>
+<span class="sourceLineNo">5512</span>                    + " doesn't exist any more. Skip loading the file(s)", ex);<a name="line.5512"></a>
+<span class="sourceLineNo">5513</span>            continue;<a name="line.5513"></a>
+<span class="sourceLineNo">5514</span>          }<a name="line.5514"></a>
+<span class="sourceLineNo">5515</span>          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {<a name="line.5515"></a>
+<span class="sourceLineNo">5516</span>            // Record latest flush time if we picked up new files<a name="line.5516"></a>
+<span class="sourceLineNo">5517</span>            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());<a name="line.5517"></a>
+<span class="sourceLineNo">5518</span>          }<a name="line.5518"></a>
+<span class="sourceLineNo">5519</span><a name="line.5519"></a>
+<span class="sourceLineNo">5520</span>          if (writestate.flushing) {<a name="line.5520"></a>
+<span class="sourceLineNo">5521</span>            // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5521"></a>
+<span class="sourceLineNo">5522</span>            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {<a name="line.5522"></a>
+<span class="sourceLineNo">5523</span>              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5523"></a>
+<span class="sourceLineNo">5524</span>                  null : this.prepareFlushResult.storeFlushCtxs.get(family);<a name="line.5524"></a>
+<span class="sourceLineNo">5525</span>              if (ctx != null) {<a name="line.5525"></a>
+<span class="sourceLineNo">5526</span>                MemStoreSize mss = store.getFlushableSize();<a name="line.5526"></a>
+<span class="sourceLineNo">5527</span>                ctx.abort();<a name="line.5527"></a>
+<span class="sourceLineNo">5528</span>                this.decrMemStoreSize(mss);<a name="line.5528"></a>
+<span class="sourceLineNo">5529</span>                this.prepareFlushResult.storeFlushCtxs.remove(family);<a name="line.5529"></a>
+<span class="sourceLineNo">5530</span>              }<a name="line.5530"></a>
+<span class="sourceLineNo">5531</span>            }<a name="line.5531"></a>
+<span class="sourceLineNo">5532</span>          }<a name="line.5532"></a>
+<span class="sourceLineNo">5533</span><a name="line.5533"></a>
+<span class="sourceLineNo">5534</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5534"></a>
+<span class="sourceLineNo">5535</span>          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);<a name="line.5535"></a>
+<span class="sourceLineNo">5536</span>          if (storeSeqId &gt; this.maxFlushedSeqId) {<a name="line.5536"></a>
+<span class="sourceLineNo">5537</span>            this.maxFlushedSeqId = storeSeqId;<a name="line.5537"></a>
+<span class="sourceLineNo">5538</span>          }<a name="line.5538"></a>
+<span class="sourceLineNo">5539</span>        }<a name="line.5539"></a>
+<span class="sourceLineNo">5540</span><a name="line.5540"></a>
+<span class="sourceLineNo">5541</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5541"></a>
+<span class="sourceLineNo">5542</span>        // prepareFlushResult<a name="line.5542"></a>
+<span class="sourceLineNo">5543</span>        dropPrepareFlushIfPossible();<a name="line.5543"></a>
 <span class="sourceLineNo">5544</span><a name="line.5544"></a>
-<span class="sourceLineNo">5545</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5545"></a>
-<span class="sourceLineNo">5546</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5546"></a>
-<span class="sourceLineNo">5547</span>        this.setReadsEnabled(true);<a name="line.5547"></a>
-<span class="sourceLineNo">5548</span><a name="line.5548"></a>
-<span class="sourceLineNo">5549</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5549"></a>
-<span class="sourceLineNo">5550</span>        // e.g. checkResources().<a name="line.5550"></a>
-<span class="sourceLineNo">5551</span>        synchronized (this) {<a name="line.5551"></a>
-<span class="sourceLineNo">5552</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5552"></a>
-<span class="sourceLineNo">5553</span>        }<a name="line.5553"></a>
-<span class="sourceLineNo">5554</span>      }<a name="line.5554"></a>
-<span class="sourceLineNo">5555</span>      logRegionFiles();<a name="line.5555"></a>
-<span class="sourceLineNo">5556</span>    } finally {<a name="line.5556"></a>
-<span class="sourceLineNo">5557</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5557"></a>
-<span class="sourceLineNo">5558</span>    }<a name="line.5558"></a>
-<span class="sourceLineNo">5559</span>  }<a name="line.5559"></a>
-<span class="sourceLineNo">5560</span><a name="line.5560"></a>
-<span class="sourceLineNo">5561</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5561"></a>
-<span class="sourceLineNo">5562</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5562"></a>
-<span class="sourceLineNo">5563</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5563"></a>
-<span class="sourceLineNo">5564</span><a name="line.5564"></a>
-<span class="sourceLineNo">5565</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5565"></a>
-<span class="sourceLineNo">5566</span>      return; // if primary nothing to do<a name="line.5566"></a>
-<span class="sourceLineNo">5567</span>    }<a name="line.5567"></a>
-<span class="sourceLineNo">5568</span><a name="line.5568"></a>
-<span class="sourceLineNo">5569</span>    if (LOG.isDebugEnabled()) {<a name="line.5569"></a>
-<span class="sourceLineNo">5570</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5570"></a>
-<span class="sourceLineNo">5571</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5571"></a>
-<span class="sourceLineNo">5572</span>    }<a name="line.5572"></a>
-<span class="sourceLineNo">5573</span>    // check if multiple families involved<a name="line.5573"></a>
-<span class="sourceLineNo">5574</span>    boolean multipleFamilies = false;<a name="line.5574"></a>
-<span class="sourceLineNo">5575</span>    byte[] family = null;<a name="line.5575"></a>
-<span class="sourceLineNo">5576</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5576"></a>
-<span class="sourceLineNo">5577</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5577"></a>
-<span class="sourceLineNo">5578</span>      if (family == null) {<a name="line.5578"></a>
-<span class="sourceLineNo">5579</span>        family = fam;<a name="line.5579"></a>
-<span class="sourceLineNo">5580</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5580"></a>
-<span class="sourceLineNo">5581</span>        multipleFamilies = true;<a name="line.5581"></a>
-<span class="sourceLineNo">5582</span>        break;<a name="line.5582"></a>
-<span class="sourceLineNo">5583</span>      }<a name="line.5583"></a>
-<span class="sourceLineNo">5584</span>    }<a name="line.5584"></a>
-<span class="sourceLineNo">5585</span><a name="line.5585"></a>
-<span class="sourceLineNo">5586</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5586"></a>
-<span class="sourceLineNo">5587</span>    try {<a name="line.5587"></a>
-<span class="sourceLineNo">5588</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5588"></a>
-<span class="sourceLineNo">5589</span>      synchronized (writestate) {<a name="line.5589"></a>
-<span class="sourceLineNo">5590</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5590"></a>
-<span class="sourceLineNo">5591</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5591"></a>
-<span class="sourceLineNo">5592</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5592"></a>
-<span class="sourceLineNo">5593</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5593"></a>
-<span class="sourceLineNo">5594</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5594"></a>
-<span class="sourceLineNo">5595</span>        // smaller than this seqId<a name="line.5595"></a>
-<span class="sourceLineNo">5596</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5596"></a>
-<span class="sourceLineNo">5597</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5597"></a>
-<span class="sourceLineNo">5598</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5598"></a>
-<span class="sourceLineNo">5599</span>              + "Skipping replaying bulkload event :"<a name="line.5599"></a>
-<span class="sourceLineNo">5600</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5600"></a>
-<span class="sourceLineNo">5601</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5601"></a>
-<span class="sourceLineNo">5602</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5602"></a>
-<span class="sourceLineNo">5603</span><a name="line.5603"></a>
-<span class="sourceLineNo">5604</span>          return;<a name="line.5604"></a>
-<span class="sourceLineNo">5605</span>        }<a name="line.5605"></a>
+<span class="sourceLineNo">5545</span>        // advance the mvcc read point so that the new flushed file is visible.<a name="line.5545"></a>
+<span class="sourceLineNo">5546</span>        mvcc.await();<a name="line.5546"></a>
+<span class="sourceLineNo">5547</span><a name="line.5547"></a>
+<span class="sourceLineNo">5548</span>        // If we were waiting for observing a flush or region opening event for not showing partial<a name="line.5548"></a>
+<span class="sourceLineNo">5549</span>        // data after a secondary region crash, we can allow reads now.<a name="line.5549"></a>
+<span class="sourceLineNo">5550</span>        this.setReadsEnabled(true);<a name="line.5550"></a>
+<span class="sourceLineNo">5551</span><a name="line.5551"></a>
+<span class="sourceLineNo">5552</span>        // C. Finally notify anyone waiting on memstore to clear:<a name="line.5552"></a>
+<span class="sourceLineNo">5553</span>        // e.g. checkResources().<a name="line.5553"></a>
+<span class="sourceLineNo">5554</span>        synchronized (this) {<a name="line.5554"></a>
+<span class="sourceLineNo">5555</span>          notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5555"></a>
+<span class="sourceLineNo">5556</span>        }<a name="line.5556"></a>
+<span class="sourceLineNo">5557</span>      }<a name="line.5557"></a>
+<span class="sourceLineNo">5558</span>      logRegionFiles();<a name="line.5558"></a>
+<span class="sourceLineNo">5559</span>    } finally {<a name="line.5559"></a>
+<span class="sourceLineNo">5560</span>      closeRegionOperation(Operation.REPLAY_EVENT);<a name="line.5560"></a>
+<span class="sourceLineNo">5561</span>    }<a name="line.5561"></a>
+<span class="sourceLineNo">5562</span>  }<a name="line.5562"></a>
+<span class="sourceLineNo">5563</span><a name="line.5563"></a>
+<span class="sourceLineNo">5564</span>  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {<a name="line.5564"></a>
+<span class="sourceLineNo">5565</span>    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),<a name="line.5565"></a>
+<span class="sourceLineNo">5566</span>      "BulkLoad marker from WAL ", bulkLoadEvent);<a name="line.5566"></a>
+<span class="sourceLineNo">5567</span><a name="line.5567"></a>
+<span class="sourceLineNo">5568</span>    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5568"></a>
+<span class="sourceLineNo">5569</span>      return; // if primary nothing to do<a name="line.5569"></a>
+<span class="sourceLineNo">5570</span>    }<a name="line.5570"></a>
+<span class="sourceLineNo">5571</span><a name="line.5571"></a>
+<span class="sourceLineNo">5572</span>    if (LOG.isDebugEnabled()) {<a name="line.5572"></a>
+<span class="sourceLineNo">5573</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5573"></a>
+<span class="sourceLineNo">5574</span>              +  "Replaying bulkload event marker " + TextFormat.shortDebugString(bulkLoadEvent));<a name="line.5574"></a>
+<span class="sourceLineNo">5575</span>    }<a name="line.5575"></a>
+<span class="sourceLineNo">5576</span>    // check if multiple families involved<a name="line.5576"></a>
+<span class="sourceLineNo">5577</span>    boolean multipleFamilies = false;<a name="line.5577"></a>
+<span class="sourceLineNo">5578</span>    byte[] family = null;<a name="line.5578"></a>
+<span class="sourceLineNo">5579</span>    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5579"></a>
+<span class="sourceLineNo">5580</span>      byte[] fam = storeDescriptor.getFamilyName().toByteArray();<a name="line.5580"></a>
+<span class="sourceLineNo">5581</span>      if (family == null) {<a name="line.5581"></a>
+<span class="sourceLineNo">5582</span>        family = fam;<a name="line.5582"></a>
+<span class="sourceLineNo">5583</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.5583"></a>
+<span class="sourceLineNo">5584</span>        multipleFamilies = true;<a name="line.5584"></a>
+<span class="sourceLineNo">5585</span>        break;<a name="line.5585"></a>
+<span class="sourceLineNo">5586</span>      }<a name="line.5586"></a>
+<span class="sourceLineNo">5587</span>    }<a name="line.5587"></a>
+<span class="sourceLineNo">5588</span><a name="line.5588"></a>
+<span class="sourceLineNo">5589</span>    startBulkRegionOperation(multipleFamilies);<a name="line.5589"></a>
+<span class="sourceLineNo">5590</span>    try {<a name="line.5590"></a>
+<span class="sourceLineNo">5591</span>      // we will use writestate as a coarse-grain lock for all the replay events<a name="line.5591"></a>
+<span class="sourceLineNo">5592</span>      synchronized (writestate) {<a name="line.5592"></a>
+<span class="sourceLineNo">5593</span>        // Replication can deliver events out of order when primary region moves or the region<a name="line.5593"></a>
+<span class="sourceLineNo">5594</span>        // server crashes, since there is no coordination between replication of different wal files<a name="line.5594"></a>
+<span class="sourceLineNo">5595</span>        // belonging to different region servers. We have to safe guard against this case by using<a name="line.5595"></a>
+<span class="sourceLineNo">5596</span>        // region open event's seqid. Since this is the first event that the region puts (after<a name="line.5596"></a>
+<span class="sourceLineNo">5597</span>        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit<a name="line.5597"></a>
+<span class="sourceLineNo">5598</span>        // smaller than this seqId<a name="line.5598"></a>
+<span class="sourceLineNo">5599</span>        if (bulkLoadEvent.getBulkloadSeqNum() &gt;= 0<a name="line.5599"></a>
+<span class="sourceLineNo">5600</span>            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()) {<a name="line.5600"></a>
+<span class="sourceLineNo">5601</span>          LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5601"></a>
+<span class="sourceLineNo">5602</span>              + "Skipping replaying bulkload event :"<a name="line.5602"></a>
+<span class="sourceLineNo">5603</span>              + TextFormat.shortDebugString(bulkLoadEvent)<a name="line.5603"></a>
+<span class="sourceLineNo">5604</span>              + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"<a name="line.5604"></a>
+<span class="sourceLineNo">5605</span>              + " =" + lastReplayedOpenRegionSeqId);<a name="line.5605"></a>
 <span class="sourceLineNo">5606</span><a name="line.5606"></a>
-<span class="sourceLineNo">5607</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5607"></a>
-<span class="sourceLineNo">5608</span>          // stores of primary may be different now<a name="line.5608"></a>
-<span class="sourceLineNo">5609</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5609"></a>
-<span class="sourceLineNo">5610</span>          HStore store = getStore(family);<a name="line.5610"></a>
-<span class="sourceLineNo">5611</span>          if (store == null) {<a name="line.5611"></a>
-<span class="sourceLineNo">5612</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5612"></a>
-<span class="sourceLineNo">5613</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5613"></a>
-<span class="sourceLineNo">5614</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5614"></a>
-<span class="sourceLineNo">5615</span>            continue;<a name="line.5615"></a>
-<span class="sourceLineNo">5616</span>          }<a name="line.5616"></a>
-<span class="sourceLineNo">5617</span><a name="line.5617"></a>
-<span class="sourceLineNo">5618</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5618"></a>
-<span class="sourceLineNo">5619</span>          for (String storeFile : storeFiles) {<a name="line.5619"></a>
-<span class="sourceLineNo">5620</span>            StoreFileInfo storeFileInfo = null;<a name="line.5620"></a>
-<span class="sourceLineNo">5621</span>            try {<a name="line.5621"></a>
-<span class="sourceLineNo">5622</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5622"></a>
-<span class="sourceLineNo">5623</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5623"></a>
-<span class="sourceLineNo">5624</span>            } catch(FileNotFoundException ex) {<a name="line.5624"></a>
-<span class="sourceLineNo">5625</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5625"></a>
-<span class="sourceLineNo">5626</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5626"></a>
-<span class="sourceLineNo">5627</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5627"></a>
-<span class="sourceLineNo">5628</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5628"></a>
-<span class="sourceLineNo">5629</span>            }<a name="line.5629"></a>
-<span class="sourceLineNo">5630</span>          }<a name="line.5630"></a>
-<span class="sourceLineNo">5631</span>        }<a name="line.5631"></a>
-<span class="sourceLineNo">5632</span>      }<a name="line.5632"></a>
-<span class="sourceLineNo">5633</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5633"></a>
-<span class="sourceLineNo">5634</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5634"></a>
+<span class="sourceLineNo">5607</span>          return;<a name="line.5607"></a>
+<span class="sourceLineNo">5608</span>        }<a name="line.5608"></a>
+<span class="sourceLineNo">5609</span><a name="line.5609"></a>
+<span class="sourceLineNo">5610</span>        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {<a name="line.5610"></a>
+<span class="sourceLineNo">5611</span>          // stores of primary may be different now<a name="line.5611"></a>
+<span class="sourceLineNo">5612</span>          family = storeDescriptor.getFamilyName().toByteArray();<a name="line.5612"></a>
+<span class="sourceLineNo">5613</span>          HStore store = getStore(family);<a name="line.5613"></a>
+<span class="sourceLineNo">5614</span>          if (store == null) {<a name="line.5614"></a>
+<span class="sourceLineNo">5615</span>            LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5615"></a>
+<span class="sourceLineNo">5616</span>                    + "Received a bulk load marker from primary, but the family is not found. "<a name="line.5616"></a>
+<span class="sourceLineNo">5617</span>                    + "Ignoring. StoreDescriptor:" + storeDescriptor);<a name="line.5617"></a>
+<span class="sourceLineNo">5618</span>            continue;<a name="line.5618"></a>
+<span class="sourceLineNo">5619</span>          }<a name="line.5619"></a>
+<span class="sourceLineNo">5620</span><a name="line.5620"></a>
+<span class="sourceLineNo">5621</span>          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();<a name="line.5621"></a>
+<span class="sourceLineNo">5622</span>          for (String storeFile : storeFiles) {<a name="line.5622"></a>
+<span class="sourceLineNo">5623</span>            StoreFileInfo storeFileInfo = null;<a name="line.5623"></a>
+<span class="sourceLineNo">5624</span>            try {<a name="line.5624"></a>
+<span class="sourceLineNo">5625</span>              storeFileInfo = fs.getStoreFileInfo(Bytes.toString(family), storeFile);<a name="line.5625"></a>
+<span class="sourceLineNo">5626</span>              store.bulkLoadHFile(storeFileInfo);<a name="line.5626"></a>
+<span class="sourceLineNo">5627</span>            } catch(FileNotFoundException ex) {<a name="line.5627"></a>
+<span class="sourceLineNo">5628</span>              LOG.warn(getRegionInfo().getEncodedName() + " : "<a name="line.5628"></a>
+<span class="sourceLineNo">5629</span>                      + ((storeFileInfo != null) ? storeFileInfo.toString() :<a name="line.5629"></a>
+<span class="sourceLineNo">5630</span>                            (new Path(Bytes.toString(family), storeFile)).toString())<a name="line.5630"></a>
+<span class="sourceLineNo">5631</span>                      + " doesn't exist any more. Skip loading the file");<a name="line.5631"></a>
+<span class="sourceLineNo">5632</span>            }<a name="line.5632"></a>
+<span class="sourceLineNo">5633</span>          }<a name="line.5633"></a>
+<span class="sourceLineNo">5634</span>        }<a name="line.5634"></a>
 <span class="sourceLineNo">5635</span>      }<a name="line.5635"></a>
-<span class="sourceLineNo">5636</span>    } finally {<a name="line.5636"></a>
-<span class="sourceLineNo">5637</span>      closeBulkRegionOperation();<a name="line.5637"></a>
-<span class="sourceLineNo">5638</span>    }<a name="line.5638"></a>
-<span class="sourceLineNo">5639</span>  }<a name="line.5639"></a>
-<span class="sourceLineNo">5640</span><a name="line.5640"></a>
-<span class="sourceLineNo">5641</span>  /**<a name="line.5641"></a>
-<span class="sourceLineNo">5642</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5642"></a>
-<span class="sourceLineNo">5643</span>   */<a name="line.5643"></a>
-<span class="sourceLineNo">5644</span>  private void dropPrepareFlushIfPossible() {<a name="line.5644"></a>
-<span class="sourceLineNo">5645</span>    if (writestate.flushing) {<a name="line.5645"></a>
-<span class="sourceLineNo">5646</span>      boolean canDrop = true;<a name="line.5646"></a>
-<span class="sourceLineNo">5647</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5647"></a>
-<span class="sourceLineNo">5648</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5648"></a>
-<span class="sourceLineNo">5649</span>            .entrySet()) {<a name="line.5649"></a>
-<span class="sourceLineNo">5650</span>          HStore store = getStore(entry.getKey());<a name="line.5650"></a>
-<span class="sourceLineNo">5651</span>          if (store == null) {<a name="line.5651"></a>
-<span class="sourceLineNo">5652</span>            continue;<a name="line.5652"></a>
-<span class="sourceLineNo">5653</span>          }<a name="line.5653"></a>
-<span class="sourceLineNo">5654</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5654"></a>
-<span class="sourceLineNo">5655</span>            canDrop = false;<a name="line.5655"></a>
-<span class="sourceLineNo">5656</span>            break;<a name="line.5656"></a>
-<span class="sourceLineNo">5657</span>          }<a name="line.5657"></a>
-<span class="sourceLineNo">5658</span>        }<a name="line.5658"></a>
-<span class="sourceLineNo">5659</span>      }<a name="line.5659"></a>
-<span class="sourceLineNo">5660</span><a name="line.5660"></a>
-<span class="sourceLineNo">5661</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5661"></a>
-<span class="sourceLineNo">5662</span>      // may not have been written or we did not receive it yet.<a name="line.5662"></a>
-<span class="sourceLineNo">5663</span>      if (canDrop) {<a name="line.5663"></a>
-<span class="sourceLineNo">5664</span>        writestate.flushing = false;<a name="line.5664"></a>
-<span class="sourceLineNo">5665</span>        this.prepareFlushResult = null;<a name="line.5665"></a>
-<span class="sourceLineNo">5666</span>      }<a name="line.5666"></a>
-<span class="sourceLineNo">5667</span>    }<a name="line.5667"></a>
-<span class="sourceLineNo">5668</span>  }<a name="line.5668"></a>
-<span class="sourceLineNo">5669</span><a name="line.5669"></a>
-<span class="sourceLineNo">5670</span>  @Override<a name="line.5670"></a>
-<span class="sourceLineNo">5671</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5671"></a>
-<span class="sourceLineNo">5672</span>    return refreshStoreFiles(false);<a name="line.5672"></a>
-<span class="sourceLineNo">5673</span>  }<a name="line.5673"></a>
-<span class="sourceLineNo">5674</span><a name="line.5674"></a>
-<span class="sourceLineNo">5675</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5675"></a>
-<span class="sourceLineNo">5676</span>      justification = "Notify is about post replay. Intentional")<a name="line.5676"></a>
-<span class="sourceLineNo">5677</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5677"></a>
-<span class="sourceLineNo">5678</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5678"></a>
-<span class="sourceLineNo">5679</span>      return false; // if primary nothing to do<a name="line.5679"></a>
-<span class="sourceLineNo">5680</span>    }<a name="line.5680"></a>
-<span class="sourceLineNo">5681</span><a name="line.5681"></a>
-<span class="sourceLineNo">5682</span>    if (LOG.isDebugEnabled()) {<a name="line.5682"></a>
-<span class="sourceLineNo">5683</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5683"></a>
-<span class="sourceLineNo">5684</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5684"></a>
-<span class="sourceLineNo">5685</span>    }<a name="line.5685"></a>
-<span class="sourceLineNo">5686</span><a name="line.5686"></a>
-<span class="sourceLineNo">5687</span>    long totalFreedDataSize = 0;<a name="line.5687"></a>
-<span class="sourceLineNo">5688</span><a name="line.5688"></a>
-<span class="sourceLineNo">5689</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5689"></a>
-<span class="sourceLineNo">5690</span><a name="line.5690"></a>
-<span class="sourceLineNo">5691</span>    startRegionOperation(); // obtain region close lock<a name="line.5691"></a>
-<span class="sourceLineNo">5692</span>    try {<a name="line.5692"></a>
-<span class="sourceLineNo">5693</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5693"></a>
-<span class="sourceLineNo">5694</span>      synchronized (writestate) {<a name="line.5694"></a>
-<span class="sourceLineNo">5695</span>        for (HStore store : stores.values()) {<a name="line.5695"></a>
-<span class="sourceLineNo">5696</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5696"></a>
-<span class="sourceLineNo">5697</span>          // MIGHT break atomic edits across column families.<a name="line.5697"></a>
-<span class="sourceLineNo">5698</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5698"></a>
-<span class="sourceLineNo">5699</span><a name="line.5699"></a>
-<span class="sourceLineNo">5700</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5700"></a>
-<span class="sourceLineNo">5701</span>          store.refreshStoreFiles();<a name="line.5701"></a>
+<span class="sourceLineNo">5636</span>      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {<a name="line.5636"></a>
+<span class="sourceLineNo">5637</span>        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());<a name="line.5637"></a>
+<span class="sourceLineNo">5638</span>      }<a name="line.5638"></a>
+<span class="sourceLineNo">5639</span>    } finally {<a name="line.5639"></a>
+<span class="sourceLineNo">5640</span>      closeBulkRegionOperation();<a name="line.5640"></a>
+<span class="sourceLineNo">5641</span>    }<a name="line.5641"></a>
+<span class="sourceLineNo">5642</span>  }<a name="line.5642"></a>
+<span class="sourceLineNo">5643</span><a name="line.5643"></a>
+<span class="sourceLineNo">5644</span>  /**<a name="line.5644"></a>
+<span class="sourceLineNo">5645</span>   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult<a name="line.5645"></a>
+<span class="sourceLineNo">5646</span>   */<a name="line.5646"></a>
+<span class="sourceLineNo">5647</span>  private void dropPrepareFlushIfPossible() {<a name="line.5647"></a>
+<span class="sourceLineNo">5648</span>    if (writestate.flushing) {<a name="line.5648"></a>
+<span class="sourceLineNo">5649</span>      boolean canDrop = true;<a name="line.5649"></a>
+<span class="sourceLineNo">5650</span>      if (prepareFlushResult.storeFlushCtxs != null) {<a name="line.5650"></a>
+<span class="sourceLineNo">5651</span>        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs<a name="line.5651"></a>
+<span class="sourceLineNo">5652</span>            .entrySet()) {<a name="line.5652"></a>
+<span class="sourceLineNo">5653</span>          HStore store = getStore(entry.getKey());<a name="line.5653"></a>
+<span class="sourceLineNo">5654</span>          if (store == null) {<a name="line.5654"></a>
+<span class="sourceLineNo">5655</span>            continue;<a name="line.5655"></a>
+<span class="sourceLineNo">5656</span>          }<a name="line.5656"></a>
+<span class="sourceLineNo">5657</span>          if (store.getSnapshotSize().getDataSize() &gt; 0) {<a name="line.5657"></a>
+<span class="sourceLineNo">5658</span>            canDrop = false;<a name="line.5658"></a>
+<span class="sourceLineNo">5659</span>            break;<a name="line.5659"></a>
+<span class="sourceLineNo">5660</span>          }<a name="line.5660"></a>
+<span class="sourceLineNo">5661</span>        }<a name="line.5661"></a>
+<span class="sourceLineNo">5662</span>      }<a name="line.5662"></a>
+<span class="sourceLineNo">5663</span><a name="line.5663"></a>
+<span class="sourceLineNo">5664</span>      // this means that all the stores in the region has finished flushing, but the WAL marker<a name="line.5664"></a>
+<span class="sourceLineNo">5665</span>      // may not have been written or we did not receive it yet.<a name="line.5665"></a>
+<span class="sourceLineNo">5666</span>      if (canDrop) {<a name="line.5666"></a>
+<span class="sourceLineNo">5667</span>        writestate.flushing = false;<a name="line.5667"></a>
+<span class="sourceLineNo">5668</span>        this.prepareFlushResult = null;<a name="line.5668"></a>
+<span class="sourceLineNo">5669</span>      }<a name="line.5669"></a>
+<span class="sourceLineNo">5670</span>    }<a name="line.5670"></a>
+<span class="sourceLineNo">5671</span>  }<a name="line.5671"></a>
+<span class="sourceLineNo">5672</span><a name="line.5672"></a>
+<span class="sourceLineNo">5673</span>  @Override<a name="line.5673"></a>
+<span class="sourceLineNo">5674</span>  public boolean refreshStoreFiles() throws IOException {<a name="line.5674"></a>
+<span class="sourceLineNo">5675</span>    return refreshStoreFiles(false);<a name="line.5675"></a>
+<span class="sourceLineNo">5676</span>  }<a name="line.5676"></a>
+<span class="sourceLineNo">5677</span><a name="line.5677"></a>
+<span class="sourceLineNo">5678</span>  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",<a name="line.5678"></a>
+<span class="sourceLineNo">5679</span>      justification = "Notify is about post replay. Intentional")<a name="line.5679"></a>
+<span class="sourceLineNo">5680</span>  protected boolean refreshStoreFiles(boolean force) throws IOException {<a name="line.5680"></a>
+<span class="sourceLineNo">5681</span>    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {<a name="line.5681"></a>
+<span class="sourceLineNo">5682</span>      return false; // if primary nothing to do<a name="line.5682"></a>
+<span class="sourceLineNo">5683</span>    }<a name="line.5683"></a>
+<span class="sourceLineNo">5684</span><a name="line.5684"></a>
+<span class="sourceLineNo">5685</span>    if (LOG.isDebugEnabled()) {<a name="line.5685"></a>
+<span class="sourceLineNo">5686</span>      LOG.debug(getRegionInfo().getEncodedName() + " : "<a name="line.5686"></a>
+<span class="sourceLineNo">5687</span>          + "Refreshing store files to see whether we can free up memstore");<a name="line.5687"></a>
+<span class="sourceLineNo">5688</span>    }<a name="line.5688"></a>
+<span class="sourceLineNo">5689</span><a name="line.5689"></a>
+<span class="sourceLineNo">5690</span>    long totalFreedDataSize = 0;<a name="line.5690"></a>
+<span class="sourceLineNo">5691</span><a name="line.5691"></a>
+<span class="sourceLineNo">5692</span>    long smallestSeqIdInStores = Long.MAX_VALUE;<a name="line.5692"></a>
+<span class="sourceLineNo">5693</span><a name="line.5693"></a>
+<span class="sourceLineNo">5694</span>    startRegionOperation(); // obtain region close lock<a name="line.5694"></a>
+<span class="sourceLineNo">5695</span>    try {<a name="line.5695"></a>
+<span class="sourceLineNo">5696</span>      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();<a name="line.5696"></a>
+<span class="sourceLineNo">5697</span>      synchronized (writestate) {<a name="line.5697"></a>
+<span class="sourceLineNo">5698</span>        for (HStore store : stores.values()) {<a name="line.5698"></a>
+<span class="sourceLineNo">5699</span>          // TODO: some stores might see new data from flush, while others do not which<a name="line.5699"></a>
+<span class="sourceLineNo">5700</span>          // MIGHT break atomic edits across column families.<a name="line.5700"></a>
+<span class="sourceLineNo">5701</span>          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);<a name="line.5701"></a>
 <span class="sourceLineNo">5702</span><a name="line.5702"></a>
-<span class="sourceLineNo">5703</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5703"></a>
-<span class="sourceLineNo">5704</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5704"></a>
-<span class="sourceLineNo">5705</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5705"></a>
-<span class="sourceLineNo">5706</span>          }<a name="line.5706"></a>
-<span class="sourceLineNo">5707</span><a name="line.5707"></a>
-<span class="sourceLineNo">5708</span>          // see whether we can drop the memstore or the snapshot<a name="line.5708"></a>
-<span class="sourceLineNo">5709</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5709"></a>
-<span class="sourceLineNo">5710</span>            if (writestate.flushing) {<a name="line.5710"></a>
-<span class="sourceLineNo">5711</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5711"></a>
-<span class="sourceLineNo">5712</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5712"></a>
-<span class="sourceLineNo">5713</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5713"></a>
-<span class="sourceLineNo">5714</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5714"></a>
-<span class="sourceLineNo">5715</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5715"></a>
-<span class="sourceLineNo">5716</span>                if (ctx != null) {<a name="line.5716"></a>
-<span class="sourceLineNo">5717</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5717"></a>
-<span class="sourceLineNo">5718</span>                  ctx.abort();<a name="line.5718"></a>
-<span class="sourceLineNo">5719</span>                  this.decrMemStoreSize(mss);<a name="line.5719"></a>
-<span class="sourceLineNo">5720</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5720"></a>
-<span class="sourceLineNo">5721</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5721"></a>
-<span class="sourceLineNo">5722</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5722"></a>
-<span class="sourceLineNo">5723</span>                }<a name="line.5723"></a>
-<span class="sourceLineNo">5724</span>              }<a name="line.5724"></a>
-<span class="sourceLineNo">5725</span>            }<a name="line.5725"></a>
-<span class="sourceLineNo">5726</span><a name="line.5726"></a>
-<span class="sourceLineNo">5727</span>            map.put(store, storeSeqId);<a name="line.5727"></a>
-<span class="sourceLineNo">5728</span>          }<a name="line.5728"></a>
-<span class="sourceLineNo">5729</span>        }<a name="line.5729"></a>
-<span class="sourceLineNo">5730</span><a name="line.5730"></a>
-<span class="sourceLineNo">5731</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5731"></a>
-<span class="sourceLineNo">5732</span>        // prepareFlushResult<a name="line.5732"></a>
-<span class="sourceLineNo">5733</span>        dropPrepareFlushIfPossible();<a name="line.5733"></a>
-<span class="sourceLineNo">5734</span><a name="line.5734"></a>
-<span class="sourceLineNo">5735</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5735"></a>
-<span class="sourceLineNo">5736</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5736"></a>
-<span class="sourceLineNo">5737</span>        for (HStore s : stores.values()) {<a name="line.5737"></a>
-<span class="sourceLineNo">5738</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5738"></a>
-<span class="sourceLineNo">5739</span>        }<a name="line.5739"></a>
-<span class="sourceLineNo">5740</span><a name="line.5740"></a>
-<span class="sourceLineNo">5741</span><a name="line.5741"></a>
-<span class="sourceLineNo">5742</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5742"></a>
-<span class="sourceLineNo">5743</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5743"></a>
-<span class="sourceLineNo">5744</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5744"></a>
-<span class="sourceLineNo">5745</span>        // that we have picked the flush files for<a name="line.5745"></a>
-<span class="sourceLineNo">5746</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5746"></a>
-<span class="sourceLineNo">5747</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5747"></a>
-<span class="sourceLineNo">5748</span>        }<a name="line.5748"></a>
-<span class="sourceLineNo">5749</span>      }<a name="line.5749"></a>
-<span class="sourceLineNo">5750</span>      if (!map.isEmpty()) {<a name="line.5750"></a>
-<span class="sourceLineNo">5751</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5751"></a>
-<span class="sourceLineNo">5752</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5752"></a>
-<span class="sourceLineNo">5753</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5753"></a>
-<span class="sourceLineNo">5754</span>              .getDataSize();<a name="line.5754"></a>
-<span class="sourceLineNo">5755</span>        }<a name="line.5755"></a>
-<span class="sourceLineNo">5756</span>      }<a name="line.5756"></a>
-<span class="sourceLineNo">5757</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5757"></a>
-<span class="sourceLineNo">5758</span>      // e.g. checkResources().<a name="line.5758"></a>
-<span class="sourceLineNo">5759</span>      synchronized (this) {<a name="line.5759"></a>
-<span class="sourceLineNo">5760</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5760"></a>
-<span class="sourceLineNo">5761</span>      }<a name="line.5761"></a>
-<span class="sourceLineNo">5762</span>      return totalFreedDataSize &gt; 0;<a name="line.5762"></a>
-<span class="sourceLineNo">5763</span>    } finally {<a name="line.5763"></a>
-<span class="sourceLineNo">5764</span>      closeRegionOperation();<a name="line.5764"></a>
-<span class="sourceLineNo">5765</span>    }<a name="line.5765"></a>
-<span class="sourceLineNo">5766</span>  }<a name="line.5766"></a>
-<span class="sourceLineNo">5767</span><a name="line.5767"></a>
-<span class="sourceLineNo">5768</span>  private void logRegionFiles() {<a name="line.5768"></a>
-<span class="sourceLineNo">5769</span>    if (LOG.isTraceEnabled()) {<a name="line.5769"></a>
-<span class="sourceLineNo">5770</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5770"></a>
-<span class="sourceLineNo">5771</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5771"></a>
-<span class="sourceLineNo">5772</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5772"></a>
-<span class="sourceLineNo">5773</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5773"></a>
-<span class="sourceLineNo">5774</span>    }<a name="line.5774"></a>
-<span class="sourceLineNo">5775</span>  }<a name="line.5775"></a>
-<span class="sourceLineNo">5776</span><a name="line.5776"></a>
-<span class="sourceLineNo">5777</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5777"></a>
-<span class="sourceLineNo">5778</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5778"></a>
-<span class="sourceLineNo">5779</span>   */<a name="line.5779"></a>
-<span class="sourceLineNo">5780</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5780"></a>
-<span class="sourceLineNo">5781</span>      throws WrongRegionException {<a name="line.5781"></a>
-<span class="sourceLineNo">5782</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5782"></a>
-<span class="sourceLineNo">5783</span>      return;<a name="line.5783"></a>
-<span class="sourceLineNo">5784</span>    }<a name="line.5784"></a>
-<span class="sourceLineNo">5785</span><a name="line.5785"></a>
-<span class="sourceLineNo">5786</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5786"></a>
-<span class="sourceLineNo">5787</span>        Bytes.equals(encodedRegionName,<a name="line.5787"></a>
-<span class="sourceLineNo">5788</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5788"></a>
-<span class="sourceLineNo">5789</span>      return;<a name="line.5789"></a>
-<span class="sourceLineNo">5790</span>    }<a name="line.5790"></a>
-<span class="sourceLineNo">5791</span><a name="line.5791"></a>
-<span class="sourceLineNo">5792</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5792"></a>
-<span class="sourceLineNo">5793</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5793"></a>
-<span class="sourceLineNo">5794</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5794"></a>
-<span class="sourceLineNo">5795</span>  }<a name="line.5795"></a>
-<span class="sourceLineNo">5796</span><a name="line.5796"></a>
-<span class="sourceLineNo">5797</span>  /**<a name="line.5797"></a>
-<span class="sourceLineNo">5798</span>   * Used by tests<a name="line.5798"></a>
-<span class="sourceLineNo">5799</span>   * @param s Store to add edit too.<a name="line.5799"></a>
-<span class="sourceLineNo">5800</span>   * @param cell Cell to add.<a name="line.5800"></a>
-<span class="sourceLineNo">5801</span>   */<a name="line.5801"></a>
-<span class="sourceLineNo">5802</span>  @VisibleForTesting<a name="line.5802"></a>
-<span class="sourceLineNo">5803</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5803"></a>
-<span class="sourceLineNo">5804</span>    s.add(cell, memstoreAccounting);<a name="line.5804"></a>
-<span class="sourceLineNo">5805</span>  }<a name="line.5805"></a>
-<span class="sourceLineNo">5806</span><a name="line.5806"></a>
-<span class="sourceLineNo">5807</span>  /**<a name="line.5807"></a>
-<span class="sourceLineNo">5808</span>   * @param p File to check.<a name="line.5808"></a>
-<span class="sourceLineNo">5809</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5809"></a>
-<span class="sourceLineNo">5810</span>   * @throws IOException<a name="line.5810"></a>
-<span class="sourceLineNo">5811</span>   */<a name="line.5811"></a>
-<span class="sourceLineNo">5812</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5812"></a>
-<span class="sourceLineNo">5813</span>      throws IOException {<a name="line.5813"></a>
-<span class="sourceLineNo">5814</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5814"></a>
-<span class="sourceLineNo">5815</span>    if (stat.getLen() &gt; 0) {<a name="line.5815"></a>
-<span class="sourceLineNo">5816</span>      return false;<a name="line.5816"></a>
-<span class="sourceLineNo">5817</span>    }<a name="line.5817"></a>
-<span class="sourceLineNo">5818</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5818"></a>
-<span class="sourceLineNo">5819</span>    fs.delete(p, false);<a name="line.5819"></a>
-<span class="sourceLineNo">5820</span>    return true;<a name="line.5820"></a>
-<span class="sourceLineNo">5821</span>  }<a name="line.5821"></a>
-<span class="sourceLineNo">5822</span><a name="line.5822"></a>
-<span class="sourceLineNo">5823</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5823"></a>
-<span class="sourceLineNo">5824</span>      throws IOException {<a name="line.5824"></a>
-<span class="sourceLineNo">5825</span>    if (family.isMobEnabled()) {<a name="line.5825"></a>
-<span class="sourceLineNo">5826</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5826"></a>
-<span class="sourceLineNo">5827</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5827"></a>
-<span class="sourceLineNo">5828</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5828"></a>
-<span class="sourceLineNo">5829</span>            " accordingly.");<a name="line.5829"></a>
-<span class="sourceLineNo">5830</span>      }<a name="line.5830"></a>
-<span class="sourceLineNo">5831</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5831"></a>
-<span class="sourceLineNo">5832</span>    }<a name="line.5832"></a>
-<span class="sourceLineNo">5833</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5833"></a>
-<span class="sourceLineNo">5834</span>  }<a name="line.5834"></a>
-<span class="sourceLineNo">5835</span><a name="line.5835"></a>
-<span class="sourceLineNo">5836</span>  @Override<a name="line.5836"></a>
-<span class="sourceLineNo">5837</span>  public HStore getStore(byte[] column) {<a name="line.5837"></a>
-<span class="sourceLineNo">5838</span>    return this.stores.get(column);<a name="line.5838"></a>
-<span class="sourceLineNo">5839</span>  }<a name="line.5839"></a>
-<span class="sourceLineNo">5840</span><a name="line.5840"></a>
-<span class="sourceLineNo">5841</span>  /**<a name="line.5841"></a>
-<span class="sourceLineNo">5842</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5842"></a>
-<span class="sourceLineNo">5843</span>   * the list.<a name="line.5843"></a>
-<span class="sourceLineNo">5844</span>   */<a name="line.5844"></a>
-<span class="sourceLineNo">5845</span>  private HStore getStore(Cell cell) {<a name="line.5845"></a>
-<span class="sourceLineNo">5846</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5846"></a>
-<span class="sourceLineNo">5847</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5847"></a>
-<span class="sourceLineNo">5848</span>  }<a name="line.5848"></a>
-<span class="sourceLineNo">5849</span><a name="line.5849"></a>
-<span class="sourceLineNo">5850</span>  @Override<a name="line.5850"></a>
-<span class="sourceLineNo">5851</span>  public List&lt;HStore&gt; getStores() {<a name="line.5851"></a>
-<span class="sourceLineNo">5852</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5852"></a>
-<span class="sourceLineNo">5853</span>  }<a name="line.5853"></a>
-<span class="sourceLineNo">5854</span><a name="line.5854"></a>
-<span class="sourceLineNo">5855</span>  @Override<a name="line.5855"></a>
-<span class="sourceLineNo">5856</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5856"></a>
-<span class="sourceLineNo">5857</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5857"></a>
-<span class="sourceLineNo">5858</span>    synchronized (closeLock) {<a name="line.5858"></a>
-<span class="sourceLineNo">5859</span>      for (byte[] column : columns) {<a name="line.5859"></a>
-<span class="sourceLineNo">5860</span>        HStore store = this.stores.get(column);<a name="line.5860"></a>
-<span class="sourceLineNo">5861</span>        if (store == null) {<a name="line.5861"></a>
-<span class="sourceLineNo">5862</span>          throw new IllegalArgumentException(<a name="line.5862"></a>
-<span class="sourceLineNo">5863</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5863"></a>
-<span class="sourceLineNo">5864</span>        }<a name="line.5864"></a>
-<span class="sourceLineNo">5865</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5865"></a>
-<span class="sourceLineNo">5866</span>        if (storeFiles == null) {<a name="line.5866"></a>
-<span class="sourceLineNo">5867</span>          continue;<a name="line.5867"></a>
-<span class="sourceLineNo">5868</span>        }<a name="line.5868"></a>
-<span class="sourceLineNo">5869</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5869"></a>
-<span class="sourceLineNo">5870</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5870"></a>
+<span class="sourceLineNo">5703</span>          // refresh the store files. This is similar to observing a region open wal marker.<a name="line.5703"></a>
+<span class="sourceLineNo">5704</span>          store.refreshStoreFiles();<a name="line.5704"></a>
+<span class="sourceLineNo">5705</span><a name="line.5705"></a>
+<span class="sourceLineNo">5706</span>          long storeSeqId = store.getMaxSequenceId().orElse(0L);<a name="line.5706"></a>
+<span class="sourceLineNo">5707</span>          if (storeSeqId &lt; smallestSeqIdInStores) {<a name="line.5707"></a>
+<span class="sourceLineNo">5708</span>            smallestSeqIdInStores = storeSeqId;<a name="line.5708"></a>
+<span class="sourceLineNo">5709</span>          }<a name="line.5709"></a>
+<span class="sourceLineNo">5710</span><a name="line.5710"></a>
+<span class="sourceLineNo">5711</span>          // see whether we can drop the memstore or the snapshot<a name="line.5711"></a>
+<span class="sourceLineNo">5712</span>          if (storeSeqId &gt; maxSeqIdBefore) {<a name="line.5712"></a>
+<span class="sourceLineNo">5713</span>            if (writestate.flushing) {<a name="line.5713"></a>
+<span class="sourceLineNo">5714</span>              // only drop memstore snapshots if they are smaller than last flush for the store<a name="line.5714"></a>
+<span class="sourceLineNo">5715</span>              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {<a name="line.5715"></a>
+<span class="sourceLineNo">5716</span>                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null ?<a name="line.5716"></a>
+<span class="sourceLineNo">5717</span>                    null : this.prepareFlushResult.storeFlushCtxs.get(<a name="line.5717"></a>
+<span class="sourceLineNo">5718</span>                            store.getColumnFamilyDescriptor().getName());<a name="line.5718"></a>
+<span class="sourceLineNo">5719</span>                if (ctx != null) {<a name="line.5719"></a>
+<span class="sourceLineNo">5720</span>                  MemStoreSize mss = store.getFlushableSize();<a name="line.5720"></a>
+<span class="sourceLineNo">5721</span>                  ctx.abort();<a name="line.5721"></a>
+<span class="sourceLineNo">5722</span>                  this.decrMemStoreSize(mss);<a name="line.5722"></a>
+<span class="sourceLineNo">5723</span>                  this.prepareFlushResult.storeFlushCtxs.<a name="line.5723"></a>
+<span class="sourceLineNo">5724</span>                      remove(store.getColumnFamilyDescriptor().getName());<a name="line.5724"></a>
+<span class="sourceLineNo">5725</span>                  totalFreedDataSize += mss.getDataSize();<a name="line.5725"></a>
+<span class="sourceLineNo">5726</span>                }<a name="line.5726"></a>
+<span class="sourceLineNo">5727</span>              }<a name="line.5727"></a>
+<span class="sourceLineNo">5728</span>            }<a name="line.5728"></a>
+<span class="sourceLineNo">5729</span><a name="line.5729"></a>
+<span class="sourceLineNo">5730</span>            map.put(store, storeSeqId);<a name="line.5730"></a>
+<span class="sourceLineNo">5731</span>          }<a name="line.5731"></a>
+<span class="sourceLineNo">5732</span>        }<a name="line.5732"></a>
+<span class="sourceLineNo">5733</span><a name="line.5733"></a>
+<span class="sourceLineNo">5734</span>        // if all stores ended up dropping their snapshots, we can safely drop the<a name="line.5734"></a>
+<span class="sourceLineNo">5735</span>        // prepareFlushResult<a name="line.5735"></a>
+<span class="sourceLineNo">5736</span>        dropPrepareFlushIfPossible();<a name="line.5736"></a>
+<span class="sourceLineNo">5737</span><a name="line.5737"></a>
+<span class="sourceLineNo">5738</span>        // advance the mvcc read point so that the new flushed files are visible.<a name="line.5738"></a>
+<span class="sourceLineNo">5739</span>        // either greater than flush seq number or they were already picked up via flush.<a name="line.5739"></a>
+<span class="sourceLineNo">5740</span>        for (HStore s : stores.values()) {<a name="line.5740"></a>
+<span class="sourceLineNo">5741</span>          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));<a name="line.5741"></a>
+<span class="sourceLineNo">5742</span>        }<a name="line.5742"></a>
+<span class="sourceLineNo">5743</span><a name="line.5743"></a>
+<span class="sourceLineNo">5744</span><a name="line.5744"></a>
+<span class="sourceLineNo">5745</span>        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely<a name="line.5745"></a>
+<span class="sourceLineNo">5746</span>        // skip all edits that are to be replayed in the future with that has a smaller seqId<a name="line.5746"></a>
+<span class="sourceLineNo">5747</span>        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits<a name="line.5747"></a>
+<span class="sourceLineNo">5748</span>        // that we have picked the flush files for<a name="line.5748"></a>
+<span class="sourceLineNo">5749</span>        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {<a name="line.5749"></a>
+<span class="sourceLineNo">5750</span>          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;<a name="line.5750"></a>
+<span class="sourceLineNo">5751</span>        }<a name="line.5751"></a>
+<span class="sourceLineNo">5752</span>      }<a name="line.5752"></a>
+<span class="sourceLineNo">5753</span>      if (!map.isEmpty()) {<a name="line.5753"></a>
+<span class="sourceLineNo">5754</span>        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {<a name="line.5754"></a>
+<span class="sourceLineNo">5755</span>          // Drop the memstore contents if they are now smaller than the latest seen flushed file<a name="line.5755"></a>
+<span class="sourceLineNo">5756</span>          totalFreedDataSize += dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey())<a name="line.5756"></a>
+<span class="sourceLineNo">5757</span>              .getDataSize();<a name="line.5757"></a>
+<span class="sourceLineNo">5758</span>        }<a name="line.5758"></a>
+<span class="sourceLineNo">5759</span>      }<a name="line.5759"></a>
+<span class="sourceLineNo">5760</span>      // C. Finally notify anyone waiting on memstore to clear:<a name="line.5760"></a>
+<span class="sourceLineNo">5761</span>      // e.g. checkResources().<a name="line.5761"></a>
+<span class="sourceLineNo">5762</span>      synchronized (this) {<a name="line.5762"></a>
+<span class="sourceLineNo">5763</span>        notifyAll(); // FindBugs NN_NAKED_NOTIFY<a name="line.5763"></a>
+<span class="sourceLineNo">5764</span>      }<a name="line.5764"></a>
+<span class="sourceLineNo">5765</span>      return totalFreedDataSize &gt; 0;<a name="line.5765"></a>
+<span class="sourceLineNo">5766</span>    } finally {<a name="line.5766"></a>
+<span class="sourceLineNo">5767</span>      closeRegionOperation();<a name="line.5767"></a>
+<span class="sourceLineNo">5768</span>    }<a name="line.5768"></a>
+<span class="sourceLineNo">5769</span>  }<a name="line.5769"></a>
+<span class="sourceLineNo">5770</span><a name="line.5770"></a>
+<span class="sourceLineNo">5771</span>  private void logRegionFiles() {<a name="line.5771"></a>
+<span class="sourceLineNo">5772</span>    if (LOG.isTraceEnabled()) {<a name="line.5772"></a>
+<span class="sourceLineNo">5773</span>      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");<a name="line.5773"></a>
+<span class="sourceLineNo">5774</span>      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)<a name="line.5774"></a>
+<span class="sourceLineNo">5775</span>          .flatMap(s -&gt; s.getStorefiles().stream())<a name="line.5775"></a>
+<span class="sourceLineNo">5776</span>          .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));<a name="line.5776"></a>
+<span class="sourceLineNo">5777</span>    }<a name="line.5777"></a>
+<span class="sourceLineNo">5778</span>  }<a name="line.5778"></a>
+<span class="sourceLineNo">5779</span><a name="line.5779"></a>
+<span class="sourceLineNo">5780</span>  /** Checks whether the given regionName is either equal to our region, or that<a name="line.5780"></a>
+<span class="sourceLineNo">5781</span>   * the regionName is the primary region to our corresponding range for the secondary replica.<a name="line.5781"></a>
+<span class="sourceLineNo">5782</span>   */<a name="line.5782"></a>
+<span class="sourceLineNo">5783</span>  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)<a name="line.5783"></a>
+<span class="sourceLineNo">5784</span>      throws WrongRegionException {<a name="line.5784"></a>
+<span class="sourceLineNo">5785</span>    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {<a name="line.5785"></a>
+<span class="sourceLineNo">5786</span>      return;<a name="line.5786"></a>
+<span class="sourceLineNo">5787</span>    }<a name="line.5787"></a>
+<span class="sourceLineNo">5788</span><a name="line.5788"></a>
+<span class="sourceLineNo">5789</span>    if (!RegionReplicaUtil.isDefaultReplica(this.getRegionInfo()) &amp;&amp;<a name="line.5789"></a>
+<span class="sourceLineNo">5790</span>        Bytes.equals(encodedRegionName,<a name="line.5790"></a>
+<span class="sourceLineNo">5791</span>          this.fs.getRegionInfoForFS().getEncodedNameAsBytes())) {<a name="line.5791"></a>
+<span class="sourceLineNo">5792</span>      return;<a name="line.5792"></a>
+<span class="sourceLineNo">5793</span>    }<a name="line.5793"></a>
+<span class="sourceLineNo">5794</span><a name="line.5794"></a>
+<span class="sourceLineNo">5795</span>    throw new WrongRegionException(exceptionMsg + payload<a name="line.5795"></a>
+<span class="sourceLineNo">5796</span>      + " targetted for region " + Bytes.toStringBinary(encodedRegionName)<a name="line.5796"></a>
+<span class="sourceLineNo">5797</span>      + " does not match this region: " + this.getRegionInfo());<a name="line.5797"></a>
+<span class="sourceLineNo">5798</span>  }<a name="line.5798"></a>
+<span class="sourceLineNo">5799</span><a name="line.5799"></a>
+<span class="sourceLineNo">5800</span>  /**<a name="line.5800"></a>
+<span class="sourceLineNo">5801</span>   * Used by tests<a name="line.5801"></a>
+<span class="sourceLineNo">5802</span>   * @param s Store to add edit too.<a name="line.5802"></a>
+<span class="sourceLineNo">5803</span>   * @param cell Cell to add.<a name="line.5803"></a>
+<span class="sourceLineNo">5804</span>   */<a name="line.5804"></a>
+<span class="sourceLineNo">5805</span>  @VisibleForTesting<a name="line.5805"></a>
+<span class="sourceLineNo">5806</span>  protected void restoreEdit(HStore s, Cell cell, MemStoreSizing memstoreAccounting) {<a name="line.5806"></a>
+<span class="sourceLineNo">5807</span>    s.add(cell, memstoreAccounting);<a name="line.5807"></a>
+<span class="sourceLineNo">5808</span>  }<a name="line.5808"></a>
+<span class="sourceLineNo">5809</span><a name="line.5809"></a>
+<span class="sourceLineNo">5810</span>  /**<a name="line.5810"></a>
+<span class="sourceLineNo">5811</span>   * @param p File to check.<a name="line.5811"></a>
+<span class="sourceLineNo">5812</span>   * @return True if file was zero-length (and if so, we'll delete it in here).<a name="line.5812"></a>
+<span class="sourceLineNo">5813</span>   * @throws IOException<a name="line.5813"></a>
+<span class="sourceLineNo">5814</span>   */<a name="line.5814"></a>
+<span class="sourceLineNo">5815</span>  private static boolean isZeroLengthThenDelete(final FileSystem fs, final Path p)<a name="line.5815"></a>
+<span class="sourceLineNo">5816</span>      throws IOException {<a name="line.5816"></a>
+<span class="sourceLineNo">5817</span>    FileStatus stat = fs.getFileStatus(p);<a name="line.5817"></a>
+<span class="sourceLineNo">5818</span>    if (stat.getLen() &gt; 0) {<a name="line.5818"></a>
+<span class="sourceLineNo">5819</span>      return false;<a name="line.5819"></a>
+<span class="sourceLineNo">5820</span>    }<a name="line.5820"></a>
+<span class="sourceLineNo">5821</span>    LOG.warn("File " + p + " is zero-length, deleting.");<a name="line.5821"></a>
+<span class="sourceLineNo">5822</span>    fs.delete(p, false);<a name="line.5822"></a>
+<span class="sourceLineNo">5823</span>    return true;<a name="line.5823"></a>
+<span class="sourceLineNo">5824</span>  }<a name="line.5824"></a>
+<span class="sourceLineNo">5825</span><a name="line.5825"></a>
+<span class="sourceLineNo">5826</span>  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)<a name="line.5826"></a>
+<span class="sourceLineNo">5827</span>      throws IOException {<a name="line.5827"></a>
+<span class="sourceLineNo">5828</span>    if (family.isMobEnabled()) {<a name="line.5828"></a>
+<span class="sourceLineNo">5829</span>      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {<a name="line.5829"></a>
+<span class="sourceLineNo">5830</span>        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS +<a name="line.5830"></a>
+<span class="sourceLineNo">5831</span>            " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY +<a name="line.5831"></a>
+<span class="sourceLineNo">5832</span>            " accordingly.");<a name="line.5832"></a>
+<span class="sourceLineNo">5833</span>      }<a name="line.5833"></a>
+<span class="sourceLineNo">5834</span>      return new HMobStore(this, family, this.conf, warmup);<a name="line.5834"></a>
+<span class="sourceLineNo">5835</span>    }<a name="line.5835"></a>
+<span class="sourceLineNo">5836</span>    return new HStore(this, family, this.conf, warmup);<a name="line.5836"></a>
+<span class="sourceLineNo">5837</span>  }<a name="line.5837"></a>
+<span class="sourceLineNo">5838</span><a name="line.5838"></a>
+<span class="sourceLineNo">5839</span>  @Override<a name="line.5839"></a>
+<span class="sourceLineNo">5840</span>  public HStore getStore(byte[] column) {<a name="line.5840"></a>
+<span class="sourceLineNo">5841</span>    return this.stores.get(column);<a name="line.5841"></a>
+<span class="sourceLineNo">5842</span>  }<a name="line.5842"></a>
+<span class="sourceLineNo">5843</span><a name="line.5843"></a>
+<span class="sourceLineNo">5844</span>  /**<a name="line.5844"></a>
+<span class="sourceLineNo">5845</span>   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on<a name="line.5845"></a>
+<span class="sourceLineNo">5846</span>   * the list.<a name="line.5846"></a>
+<span class="sourceLineNo">5847</span>   */<a name="line.5847"></a>
+<span class="sourceLineNo">5848</span>  private HStore getStore(Cell cell) {<a name="line.5848"></a>
+<span class="sourceLineNo">5849</span>    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))<a name="line.5849"></a>
+<span class="sourceLineNo">5850</span>        .map(e -&gt; e.getValue()).findFirst().orElse(null);<a name="line.5850"></a>
+<span class="sourceLineNo">5851</span>  }<a name="line.5851"></a>
+<span class="sourceLineNo">5852</span><a name="line.5852"></a>
+<span class="sourceLineNo">5853</span>  @Override<a name="line.5853"></a>
+<span class="sourceLineNo">5854</span>  public List&lt;HStore&gt; getStores() {<a name="line.5854"></a>
+<span class="sourceLineNo">5855</span>    return new ArrayList&lt;&gt;(stores.values());<a name="line.5855"></a>
+<span class="sourceLineNo">5856</span>  }<a name="line.5856"></a>
+<span class="sourceLineNo">5857</span><a name="line.5857"></a>
+<span class="sourceLineNo">5858</span>  @Override<a name="line.5858"></a>
+<span class="sourceLineNo">5859</span>  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {<a name="line.5859"></a>
+<span class="sourceLineNo">5860</span>    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.5860"></a>
+<span class="sourceLineNo">5861</span>    synchronized (closeLock) {<a name="line.5861"></a>
+<span class="sourceLineNo">5862</span>      for (byte[] column : columns) {<a name="line.5862"></a>
+<span class="sourceLineNo">5863</span>        HStore store = this.stores.get(column);<a name="line.5863"></a>
+<span class="sourceLineNo">5864</span>        if (store == null) {<a name="line.5864"></a>
+<span class="sourceLineNo">5865</span>          throw new IllegalArgumentException(<a name="line.5865"></a>
+<span class="sourceLineNo">5866</span>              "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");<a name="line.5866"></a>
+<span class="sourceLineNo">5867</span>        }<a name="line.5867"></a>
+<span class="sourceLineNo">5868</span>        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();<a name="line.5868"></a>
+<span class="sourceLineNo">5869</span>        if (storeFiles == null) {<a name="line.5869"></a>
+<span class="sourceLineNo">5870</span>          continue;<a name="line.5870"></a>
 <span class="sourceLineNo">5871</span>        }<a name="line.5871"></a>
-<span class="sourceLineNo">5872</span><a name="line.5872"></a>
-<span class="sourceLineNo">5873</span>        logRegionFiles();<a name="line.5873"></a>
-<span class="sourceLineNo">5874</span>      }<a name="line.5874"></a>
-<span class="sourceLineNo">5875</span>    }<a name="line.5875"></a>
-<span class="sourceLineNo">5876</span>    return storeFileNames;<a name="line.5876"></a>
-<span class="sourceLineNo">5877</span>  }<a name="line.5877"></a>
-<span class="sourceLineNo">5878</span><a name="line.5878"></a>
-<span class="sourceLineNo">5879</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5879"></a>
-<span class="sourceLineNo">5880</span>  // Support code<a name="line.5880"></a>
-<span class="sourceLineNo">5881</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5881"></a>
-<span class="sourceLineNo">5882</span><a name="line.5882"></a>
-<span class="sourceLineNo">5883</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5883"></a>
-<span class="sourceLineNo">5884</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5884"></a>
-<span class="sourceLineNo">5885</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5885"></a>
-<span class="sourceLineNo">5886</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5886"></a>
-<span class="sourceLineNo">5887</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5887"></a>
-<span class="sourceLineNo">5888</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5888"></a>
-<span class="sourceLineNo">5889</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5889"></a>
-<span class="sourceLineNo">5890</span>          Bytes.toStringBinary(row) + "'");<a name="line.5890"></a>
-<span class="sourceLineNo">5891</span>    }<a name="line.5891"></a>
-<span class="sourceLineNo">5892</span>  }<a name="line.5892"></a>
-<span class="sourceLineNo">5893</span><a name="line.5893"></a>
-<span class="sourceLineNo">5894</span><a name="line.5894"></a>
-<span class="sourceLineNo">5895</span>  /**<a name="line.5895"></a>
-<span class="sourceLineNo">5896</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5896"></a>
-<span class="sourceLineNo">5897</span>   * @param row Which row to lock.<a name="line.5897"></a>
-<span class="sourceLineNo">5898</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5898"></a>
-<span class="sourceLineNo">5899</span>   * @throws IOException<a name="line.5899"></a>
-<span class="sourceLineNo">5900</span>   */<a name="line.5900"></a>
-<span class="sourceLineNo">5901</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5901"></a>
-<span class="sourceLineNo">5902</span>    return getRowLock(row, false);<a name="line.5902"></a>
-<span class="sourceLineNo">5903</span>  }<a name="line.5903"></a>
-<span class="sourceLineNo">5904</span><a name="line.5904"></a>
-<span class="sourceLineNo">5905</span>  @Override<a name="line.5905"></a>
-<span class="sourceLineNo">5906</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5906"></a>
-<span class="sourceLineNo">5907</span>    checkRow(row, "row lock");<a name="line.5907"></a>
-<span class="sourceLineNo">5908</span>    return getRowLockInternal(row, readLock, null);<a name="line.5908"></a>
-<span class="sourceLineNo">5909</span>  }<a name="line.5909"></a>
-<span class="sourceLineNo">5910</span><a name="line.5910"></a>
-<span class="sourceLineNo">5911</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5911"></a>
-<span class="sourceLineNo">5912</span>      throws IOException {<a name="line.5912"></a>
-<span class="sourceLineNo">5913</span>    // create an object to use a a key in the row lock map<a name="line.5913"></a>
-<span class="sourceLineNo">5914</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5914"></a>
-<span class="sourceLineNo">5915</span><a name="line.5915"></a>
-<span class="sourceLineNo">5916</span>    RowLockContext rowLockContext = null;<a name="line.5916"></a>
-<span class="sourceLineNo">5917</span>    RowLockImpl result = null;<a name="line.5917"></a>
+<span class="sourceLineNo">5872</span>        for (HStoreFile storeFile : storeFiles) {<a name="line.5872"></a>
+<span class="sourceLineNo">5873</span>          storeFileNames.add(storeFile.getPath().toString());<a name="line.5873"></a>
+<span class="sourceLineNo">5874</span>        }<a name="line.5874"></a>
+<span class="sourceLineNo">5875</span><a name="line.5875"></a>
+<span class="sourceLineNo">5876</span>        logRegionFiles();<a name="line.5876"></a>
+<span class="sourceLineNo">5877</span>      }<a name="line.5877"></a>
+<span class="sourceLineNo">5878</span>    }<a name="line.5878"></a>
+<span class="sourceLineNo">5879</span>    return storeFileNames;<a name="line.5879"></a>
+<span class="sourceLineNo">5880</span>  }<a name="line.5880"></a>
+<span class="sourceLineNo">5881</span><a name="line.5881"></a>
+<span class="sourceLineNo">5882</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5882"></a>
+<span class="sourceLineNo">5883</span>  // Support code<a name="line.5883"></a>
+<span class="sourceLineNo">5884</span>  //////////////////////////////////////////////////////////////////////////////<a name="line.5884"></a>
+<span class="sourceLineNo">5885</span><a name="line.5885"></a>
+<span class="sourceLineNo">5886</span>  /** Make sure this is a valid row for the HRegion */<a name="line.5886"></a>
+<span class="sourceLineNo">5887</span>  void checkRow(byte[] row, String op) throws IOException {<a name="line.5887"></a>
+<span class="sourceLineNo">5888</span>    if (!rowIsInRange(getRegionInfo(), row)) {<a name="line.5888"></a>
+<span class="sourceLineNo">5889</span>      throw new WrongRegionException("Requested row out of range for " +<a name="line.5889"></a>
+<span class="sourceLineNo">5890</span>          op + " on HRegion " + this + ", startKey='" +<a name="line.5890"></a>
+<span class="sourceLineNo">5891</span>          Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='" +<a name="line.5891"></a>
+<span class="sourceLineNo">5892</span>          Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" +<a name="line.5892"></a>
+<span class="sourceLineNo">5893</span>          Bytes.toStringBinary(row) + "'");<a name="line.5893"></a>
+<span class="sourceLineNo">5894</span>    }<a name="line.5894"></a>
+<span class="sourceLineNo">5895</span>  }<a name="line.5895"></a>
+<span class="sourceLineNo">5896</span><a name="line.5896"></a>
+<span class="sourceLineNo">5897</span><a name="line.5897"></a>
+<span class="sourceLineNo">5898</span>  /**<a name="line.5898"></a>
+<span class="sourceLineNo">5899</span>   * Get an exclusive ( write lock ) lock on a given row.<a name="line.5899"></a>
+<span class="sourceLineNo">5900</span>   * @param row Which row to lock.<a name="line.5900"></a>
+<span class="sourceLineNo">5901</span>   * @return A locked RowLock. The lock is exclusive and already aqquired.<a name="line.5901"></a>
+<span class="sourceLineNo">5902</span>   * @throws IOException<a name="line.5902"></a>
+<span class="sourceLineNo">5903</span>   */<a name="line.5903"></a>
+<span class="sourceLineNo">5904</span>  public RowLock getRowLock(byte[] row) throws IOException {<a name="line.5904"></a>
+<span class="sourceLineNo">5905</span>    return getRowLock(row, false);<a name="line.5905"></a>
+<span class="sourceLineNo">5906</span>  }<a name="line.5906"></a>
+<span class="sourceLineNo">5907</span><a name="line.5907"></a>
+<span class="sourceLineNo">5908</span>  @Override<a name="line.5908"></a>
+<span class="sourceLineNo">5909</span>  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {<a name="line.5909"></a>
+<span class="sourceLineNo">5910</span>    checkRow(row, "row lock");<a name="line.5910"></a>
+<span class="sourceLineNo">5911</span>    return getRowLockInternal(row, readLock, null);<a name="line.5911"></a>
+<span class="sourceLineNo">5912</span>  }<a name="line.5912"></a>
+<span class="sourceLineNo">5913</span><a name="line.5913"></a>
+<span class="sourceLineNo">5914</span>  protected RowLock getRowLockInternal(byte[] row, boolean readLock, final RowLock prevRowLock)<a name="line.5914"></a>
+<span class="sourceLineNo">5915</span>      throws IOException {<a name="line.5915"></a>
+<span class="sourceLineNo">5916</span>    // create an object to use a a key in the row lock map<a name="line.5916"></a>
+<span class="sourceLineNo">5917</span>    HashedBytes rowKey = new HashedBytes(row);<a name="line.5917"></a>
 <span class="sourceLineNo">5918</span><a name="line.5918"></a>
-<span class="sourceLineNo">5919</span>    boolean success = false;<a name="line.5919"></a>
-<span class="sourceLineNo">5920</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5920"></a>
-<span class="sourceLineNo">5921</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5921"></a>
-<span class="sourceLineNo">5922</span>      // Keep trying until we have a lock or error out.<a name="line.5922"></a>
-<span class="sourceLineNo">5923</span>      // TODO: do we need to add a time component here?<a name="line.5923"></a>
-<span class="sourceLineNo">5924</span>      while (result == null) {<a name="line.5924"></a>
-<span class="sourceLineNo">5925</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5925"></a>
-<span class="sourceLineNo">5926</span>        // Now try an get the lock.<a name="line.5926"></a>
-<span class="sourceLineNo">5927</span>        // This can fail as<a name="line.5927"></a>
-<span class="sourceLineNo">5928</span>        if (readLock) {<a name="line.5928"></a>
-<span class="sourceLineNo">5929</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5929"></a>
-<span class="sourceLineNo">5930</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5930"></a>
-<span class="sourceLineNo">5931</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5931"></a>
-<span class="sourceLineNo">5932</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5932"></a>
-<span class="sourceLineNo">5933</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5933"></a>
-<span class="sourceLineNo">5934</span>            success = true;<a name="line.5934"></a>
-<span class="sourceLineNo">5935</span>            return prevRowLock;<a name="line.5935"></a>
-<span class="sourceLineNo">5936</span>          }<a name="line.5936"></a>
-<span class="sourceLineNo">5937</span>          result = rowLockContext.newReadLock();<a name="line.5937"></a>
-<span class="sourceLineNo">5938</span>        } else {<a name="line.5938"></a>
-<span class="sourceLineNo">5939</span>          result = rowLockContext.newWriteLock();<a name="line.5939"></a>
-<span class="sourceLineNo">5940</span>        }<a name="line.5940"></a>
-<span class="sourceLineNo">5941</span>      }<a name="line.5941"></a>
-<span class="sourceLineNo">5942</span><a name="line.5942"></a>
-<span class="sourceLineNo">5943</span>      int timeout = rowLockWaitDuration;<a name="line.5943"></a>
-<span class="sourceLineNo">5944</span>      boolean reachDeadlineFirst = false;<a name="line.5944"></a>
-<span class="sourceLineNo">5945</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5945"></a>
-<span class="sourceLineNo">5946</span>      if (call.isPresent()) {<a name="line.5946"></a>
-<span class="sourceLineNo">5947</span>        long deadline = call.get().getDeadline();<a name="line.5947"></a>
-<span class="sourceLineNo">5948</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5948"></a>
-<span class="sourceLineNo">5949</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5949"></a>
-<span class="sourceLineNo">5950</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5950"></a>
-<span class="sourceLineNo">5951</span>            reachDeadlineFirst = true;<a name="line.5951"></a>
-<span class="sourceLineNo">5952</span>            timeout = timeToDeadline;<a name="line.5952"></a>
-<span class="sourceLineNo">5953</span>          }<a name="line.5953"></a>
-<span class="sourceLineNo">5954</span>        }<a name="line.5954"></a>
-<span class="sourceLineNo">5955</span>      }<a name="line.5955"></a>
-<span class="sourceLineNo">5956</span><a name="line.5956"></a>
-<span class="sourceLineNo">5957</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5957"></a>
-<span class="sourceLineNo">5958</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5958"></a>
-<span class="sourceLineNo">5959</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5959"></a>
-<span class="sourceLineNo">5960</span>            + getRegionInfo().getEncodedName();<a name="line.5960"></a>
-<span class="sourceLineNo">5961</span>        if (reachDeadlineFirst) {<a name="line.5961"></a>
-<span class="sourceLineNo">5962</span>          throw new TimeoutIOException(message);<a name="line.5962"></a>
-<span class="sourceLineNo">5963</span>        } else {<a name="line.5963"></a>
-<span class="sourceLineNo">5964</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5964"></a>
-<span class="sourceLineNo">5965</span>          throw new IOException(message);<a name="line.5965"></a>
-<span class="sourceLineNo">5966</span>        }<a name="line.5966"></a>
-<span class="sourceLineNo">5967</span>      }<a name="line.5967"></a>
-<span class="sourceLineNo">5968</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5968"></a>
-<span class="sourceLineNo">5969</span>      success = true;<a name="line.5969"></a>
-<span class="sourceLineNo">5970</span>      return result;<a name="line.5970"></a>
-<span class="sourceLineNo">5971</span>    } catch (InterruptedException ie) {<a name="line.5971"></a>
-<span class="sourceLineNo">5972</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5972"></a>
-<span class="sourceLineNo">5973</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5973"></a>
-<span class="sourceLineNo">5974</span>      iie.initCause(ie);<a name="line.5974"></a>
-<span class="sourceLineNo">5975</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5975"></a>
-<span class="sourceLineNo">5976</span>      Thread.currentThread().interrupt();<a name="line.5976"></a>
-<span class="sourceLineNo">5977</span>      throw iie;<a name="line.5977"></a>
-<span class="sourceLineNo">5978</span>    } catch (Error error) {<a name="line.5978"></a>
-<span class="sourceLineNo">5979</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5979"></a>
-<span class="sourceLineNo">5980</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5980"></a>
-<span class="sourceLineNo">5981</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5981"></a>
-<span class="sourceLineNo">5982</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5982"></a>
-<span class="sourceLineNo">5983</span>      IOException ioe = new IOException();<a name="line.5983"></a>
-<span class="sourceLineNo">5984</span>      ioe.initCause(error);<a name="line.5984"></a>
-<span class="sourceLineNo">5985</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5985"></a>
-<span class="sourceLineNo">5986</span>      throw ioe;<a name="line.5986"></a>
-<span class="sourceLineNo">5987</span>    } finally {<a name="line.5987"></a>
-<span class="sourceLineNo">5988</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5988"></a>
-<span class="sourceLineNo">5989</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5989"></a>
-<span class="sourceLineNo">5990</span>        rowLockContext.cleanUp();<a name="line.5990"></a>
-<span class="sourceLineNo">5991</span>      }<a name="line.5991"></a>
-<span class="sourceLineNo">5992</span>    }<a name="line.5992"></a>
-<span class="sourceLineNo">5993</span>  }<a name="line.5993"></a>
-<span class="sourceLineNo">5994</span><a name="line.5994"></a>
-<span class="sourceLineNo">5995</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5995"></a>
-<span class="sourceLineNo">5996</span>    if (rowLocks != null) {<a name="line.5996"></a>
-<span class="sourceLineNo">5997</span>      for (RowLock rowLock : rowLocks) {<a name="line.5997"></a>
-<span class="sourceLineNo">5998</span>        rowLock.release();<a name="line.5998"></a>
-<span class="sourceLineNo">5999</span>      }<a name="line.5999"></a>
-<span class="sourceLineNo">6000</span>      rowLocks.clear();<a name="line.6000"></a>
-<span class="sourceLineNo">6001</span>    }<a name="line.6001"></a>
-<span class="sourceLineNo">6002</span>  }<a name="line.6002"></a>
-<span class="sourceLineNo">6003</span><a name="line.6003"></a>
-<span class="sourceLineNo">6004</span>  @VisibleForTesting<a name="line.6004"></a>
-<span class="sourceLineNo">6005</span>  public int getReadLockCount() {<a name="line.6005"></a>
-<span class="sourceLineNo">6006</span>    return lock.getReadLockCount();<a name="line.6006"></a>
-<span class="sourceLineNo">6007</span>  }<a name="line.6007"></a>
-<span class="sourceLineNo">6008</span><a name="line.6008"></a>
-<span class="sourceLineNo">6009</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6009"></a>
-<span class="sourceLineNo">6010</span>    return lockedRows;<a name="line.6010"></a>
-<span class="sourceLineNo">6011</span>  }<a name="line.6011"></a>
-<span class="sourceLineNo">6012</span><a name="line.6012"></a>
-<span class="sourceLineNo">6013</span>  @VisibleForTesting<a name="line.6013"></a>
-<span class="sourceLineNo">6014</span>  class RowLockContext {<a name="line.6014"></a>
-<span class="sourceLineNo">6015</span>    private final HashedBytes row;<a name="line.6015"></a>
-<span class="sourceLineNo">6016</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6016"></a>
-<span class="sourceLineNo">6017</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6017"></a>
-<span class="sourceLineNo">6018</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6018"></a>
-<span class="sourceLineNo">6019</span>    final Object lock = new Object();<a name="line.6019"></a>
-<span class="sourceLineNo">6020</span>    private String threadName;<a name="line.6020"></a>
-<span class="sourceLineNo">6021</span><a name="line.6021"></a>
-<span class="sourceLineNo">6022</span>    RowLockContext(HashedBytes row) {<a name="line.6022"></a>
-<span class="sourceLineNo">6023</span>      this.row = row;<a name="line.6023"></a>
-<span class="sourceLineNo">6024</span>    }<a name="line.6024"></a>
-<span class="sourceLineNo">6025</span><a name="line.6025"></a>
-<span class="sourceLineNo">6026</span>    RowLockImpl newWriteLock() {<a name="line.6026"></a>
-<span class="sourceLineNo">6027</span>      Lock l = readWriteLock.writeLock();<a name="line.6027"></a>
-<span class="sourceLineNo">6028</span>      return getRowLock(l);<a name="line.6028"></a>
-<span class="sourceLineNo">6029</span>    }<a name="line.6029"></a>
-<span class="sourceLineNo">6030</span>    RowLockImpl newReadLock() {<a name="line.6030"></a>
-<span class="sourceLineNo">6031</span>      Lock l = readWriteLock.readLock();<a name="line.6031"></a>
-<span class="sourceLineNo">6032</span>      return getRowLock(l);<a name="line.6032"></a>
-<span class="sourceLineNo">6033</span>    }<a name="line.6033"></a>
-<span class="sourceLineNo">6034</span><a name="line.6034"></a>
-<span class="sourceLineNo">6035</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6035"></a>
-<span class="sourceLineNo">6036</span>      count.incrementAndGet();<a name="line.6036"></a>
-<span class="sourceLineNo">6037</span>      synchronized (lock) {<a name="line.6037"></a>
-<span class="sourceLineNo">6038</span>        if (usable.get()) {<a name="line.6038"></a>
-<span class="sourceLineNo">6039</span>          return new RowLockImpl(this, l);<a name="line.6039"></a>
-<span class="sourceLineNo">6040</span>        } else {<a name="line.6040"></a>
-<span class="sourceLineNo">6041</span>          return null;<a name="line.6041"></a>
-<span class="sourceLineNo">6042</span>        }<a name="line.6042"></a>
-<span class="sourceLineNo">6043</span>      }<a name="line.6043"></a>
-<span class="sourceLineNo">6044</span>    }<a name="line.6044"></a>
-<span class="sourceLineNo">6045</span><a name="line.6045"></a>
-<span class="sourceLineNo">6046</span>    void cleanUp() {<a name="line.6046"></a>
-<span class="sourceLineNo">6047</span>      long c = count.decrementAndGet();<a name="line.6047"></a>
-<span class="sourceLineNo">6048</span>      if (c &lt;= 0) {<a name="line.6048"></a>
-<span class="sourceLineNo">6049</span>        synchronized (lock) {<a name="line.6049"></a>
-<span class="sourceLineNo">6050</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6050"></a>
-<span class="sourceLineNo">6051</span>            usable.set(false);<a name="line.6051"></a>
-<span class="sourceLineNo">6052</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6052"></a>
-<span class="sourceLineNo">6053</span>            assert removed == this: "we should never remove a different context";<a name="line.6053"></a>
-<span class="sourceLineNo">6054</span>          }<a name="line.6054"></a>
-<span class="sourceLineNo">6055</span>        }<a name="line.6055"></a>
-<span class="sourceLineNo">6056</span>      }<a name="line.6056"></a>
-<span class="sourceLineNo">6057</span>    }<a name="line.6057"></a>
-<span class="sourceLineNo">6058</span><a name="line.6058"></a>
-<span class="sourceLineNo">6059</span>    public void setThreadName(String threadName) {<a name="line.6059"></a>
-<span class="sourceLineNo">6060</span>      this.threadName = threadName;<a name="line.6060"></a>
-<span class="sourceLineNo">6061</span>    }<a name="line.6061"></a>
-<span class="sourceLineNo">6062</span><a name="line.6062"></a>
-<span class="sourceLineNo">6063</span>    @Override<a name="line.6063"></a>
-<span class="sourceLineNo">6064</span>    public String toString() {<a name="line.6064"></a>
-<span class="sourceLineNo">6065</span>      return "RowLockContext{" +<a name="line.6065"></a>
-<span class="sourceLineNo">6066</span>          "row=" + row +<a name="line.6066"></a>
-<span class="sourceLineNo">6067</span>          ", readWriteLock=" + readWriteLock +<a name="line.6067"></a>
-<span class="sourceLineNo">6068</span>          ", count=" + count +<a name="line.6068"></a>
-<span class="sourceLineNo">6069</span>          ", threadName=" + threadName +<a name="line.6069"></a>
-<span class="sourceLineNo">6070</span>          '}';<a name="line.6070"></a>
-<span class="sourceLineNo">6071</span>    }<a name="line.6071"></a>
-<span class="sourceLineNo">6072</span>  }<a name="line.6072"></a>
-<span class="sourceLineNo">6073</span><a name="line.6073"></a>
-<span class="sourceLineNo">6074</span>  /**<a name="line.6074"></a>
-<span class="sourceLineNo">6075</span>   * Class used to represent a lock on a row.<a name="line.6075"></a>
-<span class="sourceLineNo">6076</span>   */<a name="line.6076"></a>
-<span class="sourceLineNo">6077</span>  public static class RowLockImpl implements RowLock {<a name="line.6077"></a>
-<span class="sourceLineNo">6078</span>    private final RowLockContext context;<a name="line.6078"></a>
-<span class="sourceLineNo">6079</span>    private final Lock lock;<a name="line.6079"></a>
-<span class="sourceLineNo">6080</span><a name="line.6080"></a>
-<span class="sourceLineNo">6081</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6081"></a>
-<span class="sourceLineNo">6082</span>      this.context = context;<a name="line.6082"></a>
-<span class="sourceLineNo">6083</span>      this.lock = lock;<a name="line.6083"></a>
-<span class="sourceLineNo">6084</span>    }<a name="line.6084"></a>
-<span class="sourceLineNo">6085</span><a name="line.6085"></a>
-<span class="sourceLineNo">6086</span>    public Lock getLock() {<a name="line.6086"></a>
-<span class="sourceLineNo">6087</span>      return lock;<a name="line.6087"></a>
-<span class="sourceLineNo">6088</span>    }<a name="line.6088"></a>
-<span class="sourceLineNo">6089</span><a name="line.6089"></a>
-<span class="sourceLineNo">6090</span>    @VisibleForTesting<a name="line.6090"></a>
-<span class="sourceLineNo">6091</span>    public RowLockContext getContext() {<a name="line.6091"></a>
-<span class="sourceLineNo">6092</span>      return context;<a name="line.6092"></a>
-<span class="sourceLineNo">6093</span>    }<a name="line.6093"></a>
-<span class="sourceLineNo">6094</span><a name="line.6094"></a>
-<span class="sourceLineNo">6095</span>    @Override<a name="line.6095"></a>
-<span class="sourceLineNo">6096</span>    public void release() {<a name="line.6096"></a>
-<span class="sourceLineNo">6097</span>      lock.unlock();<a name="line.6097"></a>
-<span class="sourceLineNo">6098</span>      context.cleanUp();<a name="line.6098"></a>
-<span class="sourceLineNo">6099</span>    }<a name="line.6099"></a>
-<span class="sourceLineNo">6100</span><a name="line.6100"></a>
-<span class="sourceLineNo">6101</span>    @Override<a name="line.6101"></a>
-<span class="sourceLineNo">6102</span>    public String toString() {<a name="line.6102"></a>
-<span class="sourceLineNo">6103</span>      return "RowLockImpl{" +<a name="line.6103"></a>
-<span class="sourceLineNo">6104</span>          "context=" + context +<a name="line.6104"></a>
-<span class="sourceLineNo">6105</span>          ", lock=" + lock +<a name="line.6105"></a>
-<span class="sourceLineNo">6106</span>          '}';<a name="line.6106"></a>
-<span class="sourceLineNo">6107</span>    }<a name="line.6107"></a>
-<span class="sourceLineNo">6108</span>  }<a name="line.6108"></a>
-<span class="sourceLineNo">6109</span><a name="line.6109"></a>
-<span class="sourceLineNo">6110</span>  /**<a name="line.6110"></a>
-<span class="sourceLineNo">6111</span>   * Determines whether multiple column families are present<a name="line.6111"></a>
-<span class="sourceLineNo">6112</span>   * Precondition: familyPaths is not null<a name="line.6112"></a>
-<span class="sourceLineNo">6113</span>   *<a name="line.6113"></a>
-<span class="sourceLineNo">6114</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6114"></a>
-<span class="sourceLineNo">6115</span>   */<a name="line.6115"></a>
-<span class="sourceLineNo">6116</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6116"></a>
-<span class="sourceLineNo">6117</span>    boolean multipleFamilies = false;<a name="line.6117"></a>
-<span class="sourceLineNo">6118</span>    byte[] family = null;<a name="line.6118"></a>
-<span class="sourceLineNo">6119</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6119"></a>
-<span class="sourceLineNo">6120</span>      byte[] fam = pair.getFirst();<a name="line.6120"></a>
-<span class="sourceLineNo">6121</span>      if (family == null) {<a name="line.6121"></a>
-<span class="sourceLineNo">6122</span>        family = fam;<a name="line.6122"></a>
-<span class="sourceLineNo">6123</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6123"></a>
-<span class="sourceLineNo">6124</span>        multipleFamilies = true;<a name="line.6124"></a>
-<span class="sourceLineNo">6125</span>        break;<a name="line.6125"></a>
-<span class="sourceLineNo">6126</span>      }<a name="line.6126"></a>
-<span class="sourceLineNo">6127</span>    }<a name="line.6127"></a>
-<span class="sourceLineNo">6128</span>    return multipleFamilies;<a name="line.6128"></a>
-<span class="sourceLineNo">6129</span>  }<a name="line.6129"></a>
-<span class="sourceLineNo">6130</span><a name="line.6130"></a>
-<span class="sourceLineNo">6131</span>  /**<a name="line.6131"></a>
-<span class="sourceLineNo">6132</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6132"></a>
-<span class="sourceLineNo">6133</span>   * rows with multiple column families atomically.<a name="line.6133"></a>
-<span class="sourceLineNo">6134</span>   *<a name="line.6134"></a>
-<span class="sourceLineNo">6135</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6135"></a>
-<span class="sourceLineNo">6136</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6136"></a>
-<span class="sourceLineNo">6137</span>   * file about to be bulk loaded<a name="line.6137"></a>
-<span class="sourceLineNo">6138</span>   * @param assignSeqId<a name="line.6138"></a>
-<span class="sourceLineNo">6139</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6139"></a>
-<span class="sourceLineNo">6140</span>   * @throws IOException if failed unrecoverably.<a name="line.6140"></a>
-<span class="sourceLineNo">6141</span>   */<a name="line.6141"></a>
-<span class="sourceLineNo">6142</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6142"></a>
-<span class="sourceLineNo">6143</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6143"></a>
-<span class="sourceLineNo">6144</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6144"></a>
-<span class="sourceLineNo">6145</span>  }<a name="line.6145"></a>
-<span class="sourceLineNo">6146</span><a name="line.6146"></a>
-<span class="sourceLineNo">6147</span>  /**<a name="line.6147"></a>
-<span class="sourceLineNo">6148</span>   * Listener class to enable callers of<a name="line.6148"></a>
-<span class="sourceLineNo">6149</span>   * bulkLoadHFile() to perform any necessary<a name="line.6149"></a>
-<span class="sourceLineNo">6150</span>   * pre/post processing of a given bulkload call<a name="line.6150"></a>
-<span class="sourceLineNo">6151</span>   */<a name="line.6151"></a>
-<span class="sourceLineNo">6152</span>  public interface BulkLoadListener {<a name="line.6152"></a>
-<span class="sourceLineNo">6153</span>    /**<a name="line.6153"></a>
-<span class="sourceLineNo">6154</span>     * Called before an HFile is actually loaded<a name="line.6154"></a>
-<span class="sourceLineNo">6155</span>     * @param family family being loaded to<a name="line.6155"></a>
-<span class="sourceLineNo">6156</span>     * @param srcPath path of HFile<a name="line.6156"></a>
-<span class="sourceLineNo">6157</span>     * @return final path to be used for actual loading<a name="line.6157"></a>
-<span class="sourceLineNo">6158</span>     * @throws IOException<a name="line.6158"></a>
-<span class="sourceLineNo">6159</span>     */<a name="line.6159"></a>
-<span class="sourceLineNo">6160</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6160"></a>
-<span class="sourceLineNo">6161</span>        throws IOException;<a name="line.6161"></a>
-<span class="sourceLineNo">6162</span><a name="line.6162"></a>
-<span class="sourceLineNo">6163</span>    /**<a name="line.6163"></a>
-<span class="sourceLineNo">6164</span>     * Called after a successful HFile load<a name="line.6164"></a>
-<span class="sourceLineNo">6165</span>     * @param family family being loaded to<a name="line.6165"></a>
-<span class="sourceLineNo">6166</span>     * @param srcPath path of HFile<a name="line.6166"></a>
-<span class="sourceLineNo">6167</span>     * @throws IOException<a name="line.6167"></a>
-<span class="sourceLineNo">6168</span>     */<a name="line.6168"></a>
-<span class="sourceLineNo">6169</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6169"></a>
-<span class="sourceLineNo">6170</span><a name="line.6170"></a>
-<span class="sourceLineNo">6171</span>    /**<a name="line.6171"></a>
-<span class="sourceLineNo">6172</span>     * Called after a failed HFile load<a name="line.6172"></a>
-<span class="sourceLineNo">6173</span>     * @param family family being loaded to<a name="line.6173"></a>
-<span class="sourceLineNo">6174</span>     * @param srcPath path of HFile<a name="line.6174"></a>
-<span class="sourceLineNo">6175</span>     * @throws IOException<a name="line.6175"></a>
-<span class="sourceLineNo">6176</span>     */<a name="line.6176"></a>
-<span class="sourceLineNo">6177</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6177"></a>
-<span class="sourceLineNo">6178</span>  }<a name="line.6178"></a>
-<span class="sourceLineNo">6179</span><a name="line.6179"></a>
-<span class="sourceLineNo">6180</span>  /**<a name="line.6180"></a>
-<span class="sourceLineNo">6181</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6181"></a>
-<span class="sourceLineNo">6182</span>   * rows with multiple column families atomically.<a name="line.6182"></a>
-<span class="sourceLineNo">6183</span>   *<a name="line.6183"></a>
-<span class="sourceLineNo">6184</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6184"></a>
-<span class="sourceLineNo">6185</span>   * @param assignSeqId<a name="line.6185"></a>
-<span class="sourceLineNo">6186</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6186"></a>
-<span class="sourceLineNo">6187</span>   * file about to be bulk loaded<a name="line.6187"></a>
-<span class="sourceLineNo">6188</span>   * @param copyFile always copy hfiles if true<a name="line.6188"></a>
-<span class="sourceLineNo">6189</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6189"></a>
-<span class="sourceLineNo">6190</span>   * @throws IOException if failed unrecoverably.<a name="line.6190"></a>
-<span class="sourceLineNo">6191</span>   */<a name="line.6191"></a>
-<span class="sourceLineNo">6192</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6192"></a>
-<span class="sourceLineNo">6193</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6193"></a>
-<span class="sourceLineNo">6194</span>    long seqId = -1;<a name="line.6194"></a>
-<span class="sourceLineNo">6195</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6195"></a>
-<span class="sourceLineNo">6196</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6196"></a>
-<span class="sourceLineNo">6197</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6197"></a>
-<span class="sourceLineNo">6198</span>    // we need writeLock for multi-family bulk load<a name="line.6198"></a>
-<span class="sourceLineNo">6199</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6199"></a>
-<span class="sourceLineNo">6200</span>    boolean isSuccessful = false;<a name="line.6200"></a>
-<span class="sourceLineNo">6201</span>    try {<a name="line.6201"></a>
-<span class="sourceLineNo">6202</span>      this.writeRequestsCount.increment();<a name="line.6202"></a>
-<span class="sourceLineNo">6203</span><a name="line.6203"></a>
-<span class="sourceLineNo">6204</span>      // There possibly was a split that happened between when the split keys<a name="line.6204"></a>
-<span class="sourceLineNo">6205</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6205"></a>
-<span class="sourceLineNo">6206</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6206"></a>
-<span class="sourceLineNo">6207</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6207"></a>
-<span class="sourceLineNo">6208</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6208"></a>
-<span class="sourceLineNo">6209</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6209"></a>
-<span class="sourceLineNo">6210</span>        byte[] familyName = p.getFirst();<a name="line.6210"></a>
-<span class="sourceLineNo">6211</span>        String path = p.getSecond();<a name="line.6211"></a>
-<span class="sourceLineNo">6212</span><a name="line.6212"></a>
-<span class="sourceLineNo">6213</span>        HStore store = getStore(familyName);<a name="line.6213"></a>
-<span class="sourceLineNo">6214</span>        if (store == null) {<a name="line.6214"></a>
-<span class="sourceLineNo">6215</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6215"></a>
-<span class="sourceLineNo">6216</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6216"></a>
-<span class="sourceLineNo">6217</span>          ioes.add(ioe);<a name="line.6217"></a>
-<span class="sourceLineNo">6218</span>        } else {<a name="line.6218"></a>
-<span class="sourceLineNo">6219</span>          try {<a name="line.6219"></a>
-<span class="sourceLineNo">6220</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6220"></a>
-<span class="sourceLineNo">6221</span>          } catch (WrongRegionException wre) {<a name="line.6221"></a>
-<span class="sourceLineNo">6222</span>            // recoverable (file doesn't fit in region)<a name="line.6222"></a>
-<span class="sourceLineNo">6223</span>            failures.add(p);<a name="line.6223"></a>
-<span class="sourceLineNo">6224</span>          } catch (IOException ioe) {<a name="line.6224"></a>
-<span class="sourceLineNo">6225</span>            // unrecoverable (hdfs problem)<a name="line.6225"></a>
-<span class="sourceLineNo">6226</span>            ioes.add(ioe);<a name="line.6226"></a>
-<span class="sourceLineNo">6227</span>          }<a name="line.6227"></a>
-<span class="sourceLineNo">6228</span>        }<a name="line.6228"></a>
-<span class="sourceLineNo">6229</span>      }<a name="line.6229"></a>
-<span class="sourceLineNo">6230</span><a name="line.6230"></a>
-<span class="sourceLineNo">6231</span>      // validation failed because of some sort of IO problem.<a name="line.6231"></a>
-<span class="sourceLineNo">6232</span>      if (ioes.size() != 0) {<a name="line.6232"></a>
-<span class="sourceLineNo">6233</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6233"></a>
-<span class="sourceLineNo">6234</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6234"></a>
-<span class="sourceLineNo">6235</span>        throw e;<a name="line.6235"></a>
-<span class="sourceLineNo">6236</span>      }<a name="line.6236"></a>
-<span class="sourceLineNo">6237</span><a name="line.6237"></a>
-<span class="sourceLineNo">6238</span>      // validation failed, bail out before doing anything permanent.<a name="line.6238"></a>
-<span class="sourceLineNo">6239</span>      if (failures.size() != 0) {<a name="line.6239"></a>
-<span class="sourceLineNo">6240</span>        StringBuilder list = new StringBuilder();<a name="line.6240"></a>
-<span class="sourceLineNo">6241</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6241"></a>
-<span class="sourceLineNo">6242</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6242"></a>
-<span class="sourceLineNo">6243</span>              .append(p.getSecond());<a name="line.6243"></a>
-<span class="sourceLineNo">6244</span>        }<a name="line.6244"></a>
-<span class="sourceLineNo">6245</span>        // problem when validating<a name="line.6245"></a>
-<span class="sourceLineNo">6246</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6246"></a>
-<span class="sourceLineNo">6247</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6247"></a>
-<span class="sourceLineNo">6248</span>        return null;<a name="line.6248"></a>
-<span class="sourceLineNo">6249</span>      }<a name="line.6249"></a>
-<span class="sourceLineNo">6250</span><a name="line.6250"></a>
-<span class="sourceLineNo">6251</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6251"></a>
-<span class="sourceLineNo">6252</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6252"></a>
-<span class="sourceLineNo">6253</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6253"></a>
-<span class="sourceLineNo">6254</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6254"></a>
-<span class="sourceLineNo">6255</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6255"></a>
-<span class="sourceLineNo">6256</span>      if (assignSeqId) {<a name="line.6256"></a>
-<span class="sourceLineNo">6257</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6257"></a>
-<span class="sourceLineNo">6258</span>        if (fs.isFlushSucceeded()) {<a name="line.6258"></a>
-<span class="sourceLineNo">6259</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6259"></a>
-<span class="sourceLineNo">6260</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6260"></a>
-<span class="sourceLineNo">6261</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6261"></a>
-<span class="sourceLineNo">6262</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6262"></a>
-<span class="sourceLineNo">6263</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6263"></a>
-<span class="sourceLineNo">6264</span>          // we need to wait for that flush to complete<a name="line.6264"></a>
-<span class="sourceLineNo">6265</span>          waitForFlushes();<a name="line.6265"></a>
-<span class="sourceLineNo">6266</span>        } else {<a name="line.6266"></a>
-<span class="sourceLineNo">6267</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6267"></a>
-<span class="sourceLineNo">6268</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6268"></a>
-<span class="sourceLineNo">6269</span>        }<a name="line.6269"></a>
-<span class="sourceLineNo">6270</span>      }<a name="line.6270"></a>
-<span class="sourceLineNo">6271</span><a name="line.6271"></a>
-<span class="sourceLineNo">6272</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6272"></a>
-<span class="sourceLineNo">6273</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6273"></a>
-<span class="sourceLineNo">6274</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6274"></a>
-<span class="sourceLineNo">6275</span>        byte[] familyName = p.getFirst();<a name="line.6275"></a>
-<span class="sourceLineNo">6276</span>        String path = p.getSecond();<a name="line.6276"></a>
-<span class="sourceLineNo">6277</span>        HStore store = getStore(familyName);<a name="line.6277"></a>
-<span class="sourceLineNo">6278</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6278"></a>
-<span class="sourceLineNo">6279</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6279"></a>
-<span class="sourceLineNo">6280</span>        }<a name="line.6280"></a>
-<span class="sourceLineNo">6281</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6281"></a>
-<span class="sourceLineNo">6282</span>        try {<a name="line.6282"></a>
-<span class="sourceLineNo">6283</span>          String finalPath = path;<a name="line.6283"></a>
-<span class="sourceLineNo">6284</span>          if (bulkLoadListener != null) {<a name="line.6284"></a>
-<span class="sourceLineNo">6285</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6285"></a>
-<span class="sourceLineNo">6286</span>          }<a name="line.6286"></a>
-<span class="sourceLineNo">6287</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6287"></a>
-<span class="sourceLineNo">6288</span>          lst.add(pair);<a name="line.6288"></a>
-<span class="sourceLineNo">6289</span>        } catch (IOException ioe) {<a name="line.6289"></a>
-<span class="sourceLineNo">6290</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6290"></a>
-<span class="sourceLineNo">6291</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6291"></a>
-<span class="sourceLineNo">6292</span><a name="line.6292"></a>
-<span class="sourceLineNo">6293</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6293"></a>
-<span class="sourceLineNo">6294</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6294"></a>
-<span class="sourceLineNo">6295</span>          if (bulkLoadListener != null) {<a name="line.6295"></a>
-<span class="sourceLineNo">6296</span>            try {<a name="line.6296"></a>
-<span class="sourceLineNo">6297</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6297"></a>
-<span class="sourceLineNo">6298</span>            } catch (Exception ex) {<a name="line.6298"></a>
-<span class="sourceLineNo">6299</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6299"></a>
-<span class="sourceLineNo">6300</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6300"></a>
-<span class="sourceLineNo">6301</span>            }<a name="line.6301"></a>
-<span class="sourceLineNo">6302</span>          }<a name="line.6302"></a>
-<span class="sourceLineNo">6303</span>          throw ioe;<a name="line.6303"></a>
-<span class="sourceLineNo">6304</span>        }<a name="line.6304"></a>
-<span class="sourceLineNo">6305</span>      }<a name="line.6305"></a>
-<span class="sourceLineNo">6306</span><a name="line.6306"></a>
-<span class="sourceLineNo">6307</span>      if (this.getCoprocessorHost() != null) {<a name="line.6307"></a>
-<span class="sourceLineNo">6308</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6308"></a>
-<span class="sourceLineNo">6309</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6309"></a>
-<span class="sourceLineNo">6310</span>        }<a name="line.6310"></a>
-<span class="sourceLineNo">6311</span>      }<a name="line.6311"></a>
-<span class="sourceLineNo">6312</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6312"></a>
-<span class="sourceLineNo">6313</span>        byte[] familyName = entry.getKey();<a name="line.6313"></a>
-<span class="sourceLineNo">6314</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6314"></a>
-<span class="sourceLineNo">6315</span>          String path = p.getFirst().toString();<a name="line.6315"></a>
-<span class="sourceLineNo">6316</span>          Path commitedStoreFile = p.getSecond();<a name="line.6316"></a>
-<span class="sourceLineNo">6317</span>          HStore store = getStore(familyName);<a name="line.6317"></a>
-<span class="sourceLineNo">6318</span>          try {<a name="line.6318"></a>
-<span class="sourceLineNo">6319</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6319"></a>
-<span class="sourceLineNo">6320</span>            // Note the size of the store file<a name="line.6320"></a>
-<span class="sourceLineNo">6321</span>            try {<a name="line.6321"></a>
-<span class="sourceLineNo">6322</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6322"></a>
-<span class="sourceLineNo">6323</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6323"></a>
-<span class="sourceLineNo">6324</span>                  .getLen());<a name="line.6324"></a>
-<span class="sourceLineNo">6325</span>            } catch (IOException e) {<a name="line.6325"></a>
-<span class="sourceLineNo">6326</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6326"></a>
-<span class="sourceLineNo">6327</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6327"></a>
-<span class="sourceLineNo">6328</span>            }<a name="line.6328"></a>
-<span class="sourceLineNo">6329</span><a name="line.6329"></a>
-<span class="sourceLineNo">6330</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6330"></a>
-<span class="sourceLineNo">6331</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6331"></a>
-<span class="sourceLineNo">6332</span>            } else {<a name="line.6332"></a>
-<span class="sourceLineNo">6333</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6333"></a>
-<span class="sourceLineNo">6334</span>              storeFileNames.add(commitedStoreFile);<a name="line.6334"></a>
-<span class="sourceLineNo">6335</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6335"></a>
-<span class="sourceLineNo">6336</span>            }<a name="line.6336"></a>
-<span class="sourceLineNo">6337</span>            if (bulkLoadListener != null) {<a name="line.6337"></a>
-<span class="sourceLineNo">6338</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6338"></a>
+<span class="sourceLineNo">5919</span>    RowLockContext rowLockContext = null;<a name="line.5919"></a>
+<span class="sourceLineNo">5920</span>    RowLockImpl result = null;<a name="line.5920"></a>
+<span class="sourceLineNo">5921</span><a name="line.5921"></a>
+<span class="sourceLineNo">5922</span>    boolean success = false;<a name="line.5922"></a>
+<span class="sourceLineNo">5923</span>    try (TraceScope scope = TraceUtil.createTrace("HRegion.getRowLock")) {<a name="line.5923"></a>
+<span class="sourceLineNo">5924</span>      TraceUtil.addTimelineAnnotation("Getting a " + (readLock?"readLock":"writeLock"));<a name="line.5924"></a>
+<span class="sourceLineNo">5925</span>      // Keep trying until we have a lock or error out.<a name="line.5925"></a>
+<span class="sourceLineNo">5926</span>      // TODO: do we need to add a time component here?<a name="line.5926"></a>
+<span class="sourceLineNo">5927</span>      while (result == null) {<a name="line.5927"></a>
+<span class="sourceLineNo">5928</span>        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));<a name="line.5928"></a>
+<span class="sourceLineNo">5929</span>        // Now try an get the lock.<a name="line.5929"></a>
+<span class="sourceLineNo">5930</span>        // This can fail as<a name="line.5930"></a>
+<span class="sourceLineNo">5931</span>        if (readLock) {<a name="line.5931"></a>
+<span class="sourceLineNo">5932</span>          // For read lock, if the caller has locked the same row previously, it will not try<a name="line.5932"></a>
+<span class="sourceLineNo">5933</span>          // to acquire the same read lock. It simply returns the previous row lock.<a name="line.5933"></a>
+<span class="sourceLineNo">5934</span>          RowLockImpl prevRowLockImpl = (RowLockImpl)prevRowLock;<a name="line.5934"></a>
+<span class="sourceLineNo">5935</span>          if ((prevRowLockImpl != null) &amp;&amp; (prevRowLockImpl.getLock() ==<a name="line.5935"></a>
+<span class="sourceLineNo">5936</span>              rowLockContext.readWriteLock.readLock())) {<a name="line.5936"></a>
+<span class="sourceLineNo">5937</span>            success = true;<a name="line.5937"></a>
+<span class="sourceLineNo">5938</span>            return prevRowLock;<a name="line.5938"></a>
+<span class="sourceLineNo">5939</span>          }<a name="line.5939"></a>
+<span class="sourceLineNo">5940</span>          result = rowLockContext.newReadLock();<a name="line.5940"></a>
+<span class="sourceLineNo">5941</span>        } else {<a name="line.5941"></a>
+<span class="sourceLineNo">5942</span>          result = rowLockContext.newWriteLock();<a name="line.5942"></a>
+<span class="sourceLineNo">5943</span>        }<a name="line.5943"></a>
+<span class="sourceLineNo">5944</span>      }<a name="line.5944"></a>
+<span class="sourceLineNo">5945</span><a name="line.5945"></a>
+<span class="sourceLineNo">5946</span>      int timeout = rowLockWaitDuration;<a name="line.5946"></a>
+<span class="sourceLineNo">5947</span>      boolean reachDeadlineFirst = false;<a name="line.5947"></a>
+<span class="sourceLineNo">5948</span>      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();<a name="line.5948"></a>
+<span class="sourceLineNo">5949</span>      if (call.isPresent()) {<a name="line.5949"></a>
+<span class="sourceLineNo">5950</span>        long deadline = call.get().getDeadline();<a name="line.5950"></a>
+<span class="sourceLineNo">5951</span>        if (deadline &lt; Long.MAX_VALUE) {<a name="line.5951"></a>
+<span class="sourceLineNo">5952</span>          int timeToDeadline = (int) (deadline - System.currentTimeMillis());<a name="line.5952"></a>
+<span class="sourceLineNo">5953</span>          if (timeToDeadline &lt;= this.rowLockWaitDuration) {<a name="line.5953"></a>
+<span class="sourceLineNo">5954</span>            reachDeadlineFirst = true;<a name="line.5954"></a>
+<span class="sourceLineNo">5955</span>            timeout = timeToDeadline;<a name="line.5955"></a>
+<span class="sourceLineNo">5956</span>          }<a name="line.5956"></a>
+<span class="sourceLineNo">5957</span>        }<a name="line.5957"></a>
+<span class="sourceLineNo">5958</span>      }<a name="line.5958"></a>
+<span class="sourceLineNo">5959</span><a name="line.5959"></a>
+<span class="sourceLineNo">5960</span>      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {<a name="line.5960"></a>
+<span class="sourceLineNo">5961</span>        TraceUtil.addTimelineAnnotation("Failed to get row lock");<a name="line.5961"></a>
+<span class="sourceLineNo">5962</span>        String message = "Timed out waiting for lock for row: " + rowKey + " in region "<a name="line.5962"></a>
+<span class="sourceLineNo">5963</span>            + getRegionInfo().getEncodedName();<a name="line.5963"></a>
+<span class="sourceLineNo">5964</span>        if (reachDeadlineFirst) {<a name="line.5964"></a>
+<span class="sourceLineNo">5965</span>          throw new TimeoutIOException(message);<a name="line.5965"></a>
+<span class="sourceLineNo">5966</span>        } else {<a name="line.5966"></a>
+<span class="sourceLineNo">5967</span>          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.<a name="line.5967"></a>
+<span class="sourceLineNo">5968</span>          throw new IOException(message);<a name="line.5968"></a>
+<span class="sourceLineNo">5969</span>        }<a name="line.5969"></a>
+<span class="sourceLineNo">5970</span>      }<a name="line.5970"></a>
+<span class="sourceLineNo">5971</span>      rowLockContext.setThreadName(Thread.currentThread().getName());<a name="line.5971"></a>
+<span class="sourceLineNo">5972</span>      success = true;<a name="line.5972"></a>
+<span class="sourceLineNo">5973</span>      return result;<a name="line.5973"></a>
+<span class="sourceLineNo">5974</span>    } catch (InterruptedException ie) {<a name="line.5974"></a>
+<span class="sourceLineNo">5975</span>      LOG.warn("Thread interrupted waiting for lock on row: " + rowKey);<a name="line.5975"></a>
+<span class="sourceLineNo">5976</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.5976"></a>
+<span class="sourceLineNo">5977</span>      iie.initCause(ie);<a name="line.5977"></a>
+<span class="sourceLineNo">5978</span>      TraceUtil.addTimelineAnnotation("Interrupted exception getting row lock");<a name="line.5978"></a>
+<span class="sourceLineNo">5979</span>      Thread.currentThread().interrupt();<a name="line.5979"></a>
+<span class="sourceLineNo">5980</span>      throw iie;<a name="line.5980"></a>
+<span class="sourceLineNo">5981</span>    } catch (Error error) {<a name="line.5981"></a>
+<span class="sourceLineNo">5982</span>      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count<a name="line.5982"></a>
+<span class="sourceLineNo">5983</span>      // is reached, it will throw out an Error. This Error needs to be caught so it can<a name="line.5983"></a>
+<span class="sourceLineNo">5984</span>      // go ahead to process the minibatch with lock acquired.<a name="line.5984"></a>
+<span class="sourceLineNo">5985</span>      LOG.warn("Error to get row lock for " + Bytes.toStringBinary(row) + ", cause: " + error);<a name="line.5985"></a>
+<span class="sourceLineNo">5986</span>      IOException ioe = new IOException();<a name="line.5986"></a>
+<span class="sourceLineNo">5987</span>      ioe.initCause(error);<a name="line.5987"></a>
+<span class="sourceLineNo">5988</span>      TraceUtil.addTimelineAnnotation("Error getting row lock");<a name="line.5988"></a>
+<span class="sourceLineNo">5989</span>      throw ioe;<a name="line.5989"></a>
+<span class="sourceLineNo">5990</span>    } finally {<a name="line.5990"></a>
+<span class="sourceLineNo">5991</span>      // Clean up the counts just in case this was the thing keeping the context alive.<a name="line.5991"></a>
+<span class="sourceLineNo">5992</span>      if (!success &amp;&amp; rowLockContext != null) {<a name="line.5992"></a>
+<span class="sourceLineNo">5993</span>        rowLockContext.cleanUp();<a name="line.5993"></a>
+<span class="sourceLineNo">5994</span>      }<a name="line.5994"></a>
+<span class="sourceLineNo">5995</span>    }<a name="line.5995"></a>
+<span class="sourceLineNo">5996</span>  }<a name="line.5996"></a>
+<span class="sourceLineNo">5997</span><a name="line.5997"></a>
+<span class="sourceLineNo">5998</span>  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {<a name="line.5998"></a>
+<span class="sourceLineNo">5999</span>    if (rowLocks != null) {<a name="line.5999"></a>
+<span class="sourceLineNo">6000</span>      for (RowLock rowLock : rowLocks) {<a name="line.6000"></a>
+<span class="sourceLineNo">6001</span>        rowLock.release();<a name="line.6001"></a>
+<span class="sourceLineNo">6002</span>      }<a name="line.6002"></a>
+<span class="sourceLineNo">6003</span>      rowLocks.clear();<a name="line.6003"></a>
+<span class="sourceLineNo">6004</span>    }<a name="line.6004"></a>
+<span class="sourceLineNo">6005</span>  }<a name="line.6005"></a>
+<span class="sourceLineNo">6006</span><a name="line.6006"></a>
+<span class="sourceLineNo">6007</span>  @VisibleForTesting<a name="line.6007"></a>
+<span class="sourceLineNo">6008</span>  public int getReadLockCount() {<a name="line.6008"></a>
+<span class="sourceLineNo">6009</span>    return lock.getReadLockCount();<a name="line.6009"></a>
+<span class="sourceLineNo">6010</span>  }<a name="line.6010"></a>
+<span class="sourceLineNo">6011</span><a name="line.6011"></a>
+<span class="sourceLineNo">6012</span>  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {<a name="line.6012"></a>
+<span class="sourceLineNo">6013</span>    return lockedRows;<a name="line.6013"></a>
+<span class="sourceLineNo">6014</span>  }<a name="line.6014"></a>
+<span class="sourceLineNo">6015</span><a name="line.6015"></a>
+<span class="sourceLineNo">6016</span>  @VisibleForTesting<a name="line.6016"></a>
+<span class="sourceLineNo">6017</span>  class RowLockContext {<a name="line.6017"></a>
+<span class="sourceLineNo">6018</span>    private final HashedBytes row;<a name="line.6018"></a>
+<span class="sourceLineNo">6019</span>    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);<a name="line.6019"></a>
+<span class="sourceLineNo">6020</span>    final AtomicBoolean usable = new AtomicBoolean(true);<a name="line.6020"></a>
+<span class="sourceLineNo">6021</span>    final AtomicInteger count = new AtomicInteger(0);<a name="line.6021"></a>
+<span class="sourceLineNo">6022</span>    final Object lock = new Object();<a name="line.6022"></a>
+<span class="sourceLineNo">6023</span>    private String threadName;<a name="line.6023"></a>
+<span class="sourceLineNo">6024</span><a name="line.6024"></a>
+<span class="sourceLineNo">6025</span>    RowLockContext(HashedBytes row) {<a name="line.6025"></a>
+<span class="sourceLineNo">6026</span>      this.row = row;<a name="line.6026"></a>
+<span class="sourceLineNo">6027</span>    }<a name="line.6027"></a>
+<span class="sourceLineNo">6028</span><a name="line.6028"></a>
+<span class="sourceLineNo">6029</span>    RowLockImpl newWriteLock() {<a name="line.6029"></a>
+<span class="sourceLineNo">6030</span>      Lock l = readWriteLock.writeLock();<a name="line.6030"></a>
+<span class="sourceLineNo">6031</span>      return getRowLock(l);<a name="line.6031"></a>
+<span class="sourceLineNo">6032</span>    }<a name="line.6032"></a>
+<span class="sourceLineNo">6033</span>    RowLockImpl newReadLock() {<a name="line.6033"></a>
+<span class="sourceLineNo">6034</span>      Lock l = readWriteLock.readLock();<a name="line.6034"></a>
+<span class="sourceLineNo">6035</span>      return getRowLock(l);<a name="line.6035"></a>
+<span class="sourceLineNo">6036</span>    }<a name="line.6036"></a>
+<span class="sourceLineNo">6037</span><a name="line.6037"></a>
+<span class="sourceLineNo">6038</span>    private RowLockImpl getRowLock(Lock l) {<a name="line.6038"></a>
+<span class="sourceLineNo">6039</span>      count.incrementAndGet();<a name="line.6039"></a>
+<span class="sourceLineNo">6040</span>      synchronized (lock) {<a name="line.6040"></a>
+<span class="sourceLineNo">6041</span>        if (usable.get()) {<a name="line.6041"></a>
+<span class="sourceLineNo">6042</span>          return new RowLockImpl(this, l);<a name="line.6042"></a>
+<span class="sourceLineNo">6043</span>        } else {<a name="line.6043"></a>
+<span class="sourceLineNo">6044</span>          return null;<a name="line.6044"></a>
+<span class="sourceLineNo">6045</span>        }<a name="line.6045"></a>
+<span class="sourceLineNo">6046</span>      }<a name="line.6046"></a>
+<span class="sourceLineNo">6047</span>    }<a name="line.6047"></a>
+<span class="sourceLineNo">6048</span><a name="line.6048"></a>
+<span class="sourceLineNo">6049</span>    void cleanUp() {<a name="line.6049"></a>
+<span class="sourceLineNo">6050</span>      long c = count.decrementAndGet();<a name="line.6050"></a>
+<span class="sourceLineNo">6051</span>      if (c &lt;= 0) {<a name="line.6051"></a>
+<span class="sourceLineNo">6052</span>        synchronized (lock) {<a name="line.6052"></a>
+<span class="sourceLineNo">6053</span>          if (count.get() &lt;= 0 &amp;&amp; usable.get()){ // Don't attempt to remove row if already removed<a name="line.6053"></a>
+<span class="sourceLineNo">6054</span>            usable.set(false);<a name="line.6054"></a>
+<span class="sourceLineNo">6055</span>            RowLockContext removed = lockedRows.remove(row);<a name="line.6055"></a>
+<span class="sourceLineNo">6056</span>            assert removed == this: "we should never remove a different context";<a name="line.6056"></a>
+<span class="sourceLineNo">6057</span>          }<a name="line.6057"></a>
+<span class="sourceLineNo">6058</span>        }<a name="line.6058"></a>
+<span class="sourceLineNo">6059</span>      }<a name="line.6059"></a>
+<span class="sourceLineNo">6060</span>    }<a name="line.6060"></a>
+<span class="sourceLineNo">6061</span><a name="line.6061"></a>
+<span class="sourceLineNo">6062</span>    public void setThreadName(String threadName) {<a name="line.6062"></a>
+<span class="sourceLineNo">6063</span>      this.threadName = threadName;<a name="line.6063"></a>
+<span class="sourceLineNo">6064</span>    }<a name="line.6064"></a>
+<span class="sourceLineNo">6065</span><a name="line.6065"></a>
+<span class="sourceLineNo">6066</span>    @Override<a name="line.6066"></a>
+<span class="sourceLineNo">6067</span>    public String toString() {<a name="line.6067"></a>
+<span class="sourceLineNo">6068</span>      return "RowLockContext{" +<a name="line.6068"></a>
+<span class="sourceLineNo">6069</span>          "row=" + row +<a name="line.6069"></a>
+<span class="sourceLineNo">6070</span>          ", readWriteLock=" + readWriteLock +<a name="line.6070"></a>
+<span class="sourceLineNo">6071</span>          ", count=" + count +<a name="line.6071"></a>
+<span class="sourceLineNo">6072</span>          ", threadName=" + threadName +<a name="line.6072"></a>
+<span class="sourceLineNo">6073</span>          '}';<a name="line.6073"></a>
+<span class="sourceLineNo">6074</span>    }<a name="line.6074"></a>
+<span class="sourceLineNo">6075</span>  }<a name="line.6075"></a>
+<span class="sourceLineNo">6076</span><a name="line.6076"></a>
+<span class="sourceLineNo">6077</span>  /**<a name="line.6077"></a>
+<span class="sourceLineNo">6078</span>   * Class used to represent a lock on a row.<a name="line.6078"></a>
+<span class="sourceLineNo">6079</span>   */<a name="line.6079"></a>
+<span class="sourceLineNo">6080</span>  public static class RowLockImpl implements RowLock {<a name="line.6080"></a>
+<span class="sourceLineNo">6081</span>    private final RowLockContext context;<a name="line.6081"></a>
+<span class="sourceLineNo">6082</span>    private final Lock lock;<a name="line.6082"></a>
+<span class="sourceLineNo">6083</span><a name="line.6083"></a>
+<span class="sourceLineNo">6084</span>    public RowLockImpl(RowLockContext context, Lock lock) {<a name="line.6084"></a>
+<span class="sourceLineNo">6085</span>      this.context = context;<a name="line.6085"></a>
+<span class="sourceLineNo">6086</span>      this.lock = lock;<a name="line.6086"></a>
+<span class="sourceLineNo">6087</span>    }<a name="line.6087"></a>
+<span class="sourceLineNo">6088</span><a name="line.6088"></a>
+<span class="sourceLineNo">6089</span>    public Lock getLock() {<a name="line.6089"></a>
+<span class="sourceLineNo">6090</span>      return lock;<a name="line.6090"></a>
+<span class="sourceLineNo">6091</span>    }<a name="line.6091"></a>
+<span class="sourceLineNo">6092</span><a name="line.6092"></a>
+<span class="sourceLineNo">6093</span>    @VisibleForTesting<a name="line.6093"></a>
+<span class="sourceLineNo">6094</span>    public RowLockContext getContext() {<a name="line.6094"></a>
+<span class="sourceLineNo">6095</span>      return context;<a name="line.6095"></a>
+<span class="sourceLineNo">6096</span>    }<a name="line.6096"></a>
+<span class="sourceLineNo">6097</span><a name="line.6097"></a>
+<span class="sourceLineNo">6098</span>    @Override<a name="line.6098"></a>
+<span class="sourceLineNo">6099</span>    public void release() {<a name="line.6099"></a>
+<span class="sourceLineNo">6100</span>      lock.unlock();<a name="line.6100"></a>
+<span class="sourceLineNo">6101</span>      context.cleanUp();<a name="line.6101"></a>
+<span class="sourceLineNo">6102</span>    }<a name="line.6102"></a>
+<span class="sourceLineNo">6103</span><a name="line.6103"></a>
+<span class="sourceLineNo">6104</span>    @Override<a name="line.6104"></a>
+<span class="sourceLineNo">6105</span>    public String toString() {<a name="line.6105"></a>
+<span class="sourceLineNo">6106</span>      return "RowLockImpl{" +<a name="line.6106"></a>
+<span class="sourceLineNo">6107</span>          "context=" + context +<a name="line.6107"></a>
+<span class="sourceLineNo">6108</span>          ", lock=" + lock +<a name="line.6108"></a>
+<span class="sourceLineNo">6109</span>          '}';<a name="line.6109"></a>
+<span class="sourceLineNo">6110</span>    }<a name="line.6110"></a>
+<span class="sourceLineNo">6111</span>  }<a name="line.6111"></a>
+<span class="sourceLineNo">6112</span><a name="line.6112"></a>
+<span class="sourceLineNo">6113</span>  /**<a name="line.6113"></a>
+<span class="sourceLineNo">6114</span>   * Determines whether multiple column families are present<a name="line.6114"></a>
+<span class="sourceLineNo">6115</span>   * Precondition: familyPaths is not null<a name="line.6115"></a>
+<span class="sourceLineNo">6116</span>   *<a name="line.6116"></a>
+<span class="sourceLineNo">6117</span>   * @param familyPaths List of (column family, hfilePath)<a name="line.6117"></a>
+<span class="sourceLineNo">6118</span>   */<a name="line.6118"></a>
+<span class="sourceLineNo">6119</span>  private static boolean hasMultipleColumnFamilies(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths) {<a name="line.6119"></a>
+<span class="sourceLineNo">6120</span>    boolean multipleFamilies = false;<a name="line.6120"></a>
+<span class="sourceLineNo">6121</span>    byte[] family = null;<a name="line.6121"></a>
+<span class="sourceLineNo">6122</span>    for (Pair&lt;byte[], String&gt; pair : familyPaths) {<a name="line.6122"></a>
+<span class="sourceLineNo">6123</span>      byte[] fam = pair.getFirst();<a name="line.6123"></a>
+<span class="sourceLineNo">6124</span>      if (family == null) {<a name="line.6124"></a>
+<span class="sourceLineNo">6125</span>        family = fam;<a name="line.6125"></a>
+<span class="sourceLineNo">6126</span>      } else if (!Bytes.equals(family, fam)) {<a name="line.6126"></a>
+<span class="sourceLineNo">6127</span>        multipleFamilies = true;<a name="line.6127"></a>
+<span class="sourceLineNo">6128</span>        break;<a name="line.6128"></a>
+<span class="sourceLineNo">6129</span>      }<a name="line.6129"></a>
+<span class="sourceLineNo">6130</span>    }<a name="line.6130"></a>
+<span class="sourceLineNo">6131</span>    return multipleFamilies;<a name="line.6131"></a>
+<span class="sourceLineNo">6132</span>  }<a name="line.6132"></a>
+<span class="sourceLineNo">6133</span><a name="line.6133"></a>
+<span class="sourceLineNo">6134</span>  /**<a name="line.6134"></a>
+<span class="sourceLineNo">6135</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6135"></a>
+<span class="sourceLineNo">6136</span>   * rows with multiple column families atomically.<a name="line.6136"></a>
+<span class="sourceLineNo">6137</span>   *<a name="line.6137"></a>
+<span class="sourceLineNo">6138</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6138"></a>
+<span class="sourceLineNo">6139</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6139"></a>
+<span class="sourceLineNo">6140</span>   * file about to be bulk loaded<a name="line.6140"></a>
+<span class="sourceLineNo">6141</span>   * @param assignSeqId<a name="line.6141"></a>
+<span class="sourceLineNo">6142</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6142"></a>
+<span class="sourceLineNo">6143</span>   * @throws IOException if failed unrecoverably.<a name="line.6143"></a>
+<span class="sourceLineNo">6144</span>   */<a name="line.6144"></a>
+<span class="sourceLineNo">6145</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths, boolean assignSeqId,<a name="line.6145"></a>
+<span class="sourceLineNo">6146</span>      BulkLoadListener bulkLoadListener) throws IOException {<a name="line.6146"></a>
+<span class="sourceLineNo">6147</span>    return bulkLoadHFiles(familyPaths, assignSeqId, bulkLoadListener, false);<a name="line.6147"></a>
+<span class="sourceLineNo">6148</span>  }<a name="line.6148"></a>
+<span class="sourceLineNo">6149</span><a name="line.6149"></a>
+<span class="sourceLineNo">6150</span>  /**<a name="line.6150"></a>
+<span class="sourceLineNo">6151</span>   * Listener class to enable callers of<a name="line.6151"></a>
+<span class="sourceLineNo">6152</span>   * bulkLoadHFile() to perform any necessary<a name="line.6152"></a>
+<span class="sourceLineNo">6153</span>   * pre/post processing of a given bulkload call<a name="line.6153"></a>
+<span class="sourceLineNo">6154</span>   */<a name="line.6154"></a>
+<span class="sourceLineNo">6155</span>  public interface BulkLoadListener {<a name="line.6155"></a>
+<span class="sourceLineNo">6156</span>    /**<a name="line.6156"></a>
+<span class="sourceLineNo">6157</span>     * Called before an HFile is actually loaded<a name="line.6157"></a>
+<span class="sourceLineNo">6158</span>     * @param family family being loaded to<a name="line.6158"></a>
+<span class="sourceLineNo">6159</span>     * @param srcPath path of HFile<a name="line.6159"></a>
+<span class="sourceLineNo">6160</span>     * @return final path to be used for actual loading<a name="line.6160"></a>
+<span class="sourceLineNo">6161</span>     * @throws IOException<a name="line.6161"></a>
+<span class="sourceLineNo">6162</span>     */<a name="line.6162"></a>
+<span class="sourceLineNo">6163</span>    String prepareBulkLoad(byte[] family, String srcPath, boolean copyFile)<a name="line.6163"></a>
+<span class="sourceLineNo">6164</span>        throws IOException;<a name="line.6164"></a>
+<span class="sourceLineNo">6165</span><a name="line.6165"></a>
+<span class="sourceLineNo">6166</span>    /**<a name="line.6166"></a>
+<span class="sourceLineNo">6167</span>     * Called after a successful HFile load<a name="line.6167"></a>
+<span class="sourceLineNo">6168</span>     * @param family family being loaded to<a name="line.6168"></a>
+<span class="sourceLineNo">6169</span>     * @param srcPath path of HFile<a name="line.6169"></a>
+<span class="sourceLineNo">6170</span>     * @throws IOException<a name="line.6170"></a>
+<span class="sourceLineNo">6171</span>     */<a name="line.6171"></a>
+<span class="sourceLineNo">6172</span>    void doneBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6172"></a>
+<span class="sourceLineNo">6173</span><a name="line.6173"></a>
+<span class="sourceLineNo">6174</span>    /**<a name="line.6174"></a>
+<span class="sourceLineNo">6175</span>     * Called after a failed HFile load<a name="line.6175"></a>
+<span class="sourceLineNo">6176</span>     * @param family family being loaded to<a name="line.6176"></a>
+<span class="sourceLineNo">6177</span>     * @param srcPath path of HFile<a name="line.6177"></a>
+<span class="sourceLineNo">6178</span>     * @throws IOException<a name="line.6178"></a>
+<span class="sourceLineNo">6179</span>     */<a name="line.6179"></a>
+<span class="sourceLineNo">6180</span>    void failedBulkLoad(byte[] family, String srcPath) throws IOException;<a name="line.6180"></a>
+<span class="sourceLineNo">6181</span>  }<a name="line.6181"></a>
+<span class="sourceLineNo">6182</span><a name="line.6182"></a>
+<span class="sourceLineNo">6183</span>  /**<a name="line.6183"></a>
+<span class="sourceLineNo">6184</span>   * Attempts to atomically load a group of hfiles.  This is critical for loading<a name="line.6184"></a>
+<span class="sourceLineNo">6185</span>   * rows with multiple column families atomically.<a name="line.6185"></a>
+<span class="sourceLineNo">6186</span>   *<a name="line.6186"></a>
+<span class="sourceLineNo">6187</span>   * @param familyPaths List of Pair&amp;lt;byte[] column family, String hfilePath&amp;gt;<a name="line.6187"></a>
+<span class="sourceLineNo">6188</span>   * @param assignSeqId<a name="line.6188"></a>
+<span class="sourceLineNo">6189</span>   * @param bulkLoadListener Internal hooks enabling massaging/preparation of a<a name="line.6189"></a>
+<span class="sourceLineNo">6190</span>   * file about to be bulk loaded<a name="line.6190"></a>
+<span class="sourceLineNo">6191</span>   * @param copyFile always copy hfiles if true<a name="line.6191"></a>
+<span class="sourceLineNo">6192</span>   * @return Map from family to List of store file paths if successful, null if failed recoverably<a name="line.6192"></a>
+<span class="sourceLineNo">6193</span>   * @throws IOException if failed unrecoverably.<a name="line.6193"></a>
+<span class="sourceLineNo">6194</span>   */<a name="line.6194"></a>
+<span class="sourceLineNo">6195</span>  public Map&lt;byte[], List&lt;Path&gt;&gt; bulkLoadHFiles(Collection&lt;Pair&lt;byte[], String&gt;&gt; familyPaths,<a name="line.6195"></a>
+<span class="sourceLineNo">6196</span>      boolean assignSeqId, BulkLoadListener bulkLoadListener, boolean copyFile) throws IOException {<a name="line.6196"></a>
+<span class="sourceLineNo">6197</span>    long seqId = -1;<a name="line.6197"></a>
+<span class="sourceLineNo">6198</span>    Map&lt;byte[], List&lt;Path&gt;&gt; storeFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6198"></a>
+<span class="sourceLineNo">6199</span>    Map&lt;String, Long&gt; storeFilesSizes = new HashMap&lt;&gt;();<a name="line.6199"></a>
+<span class="sourceLineNo">6200</span>    Preconditions.checkNotNull(familyPaths);<a name="line.6200"></a>
+<span class="sourceLineNo">6201</span>    // we need writeLock for multi-family bulk load<a name="line.6201"></a>
+<span class="sourceLineNo">6202</span>    startBulkRegionOperation(hasMultipleColumnFamilies(familyPaths));<a name="line.6202"></a>
+<span class="sourceLineNo">6203</span>    boolean isSuccessful = false;<a name="line.6203"></a>
+<span class="sourceLineNo">6204</span>    try {<a name="line.6204"></a>
+<span class="sourceLineNo">6205</span>      this.writeRequestsCount.increment();<a name="line.6205"></a>
+<span class="sourceLineNo">6206</span><a name="line.6206"></a>
+<span class="sourceLineNo">6207</span>      // There possibly was a split that happened between when the split keys<a name="line.6207"></a>
+<span class="sourceLineNo">6208</span>      // were gathered and before the HRegion's write lock was taken.  We need<a name="line.6208"></a>
+<span class="sourceLineNo">6209</span>      // to validate the HFile region before attempting to bulk load all of them<a name="line.6209"></a>
+<span class="sourceLineNo">6210</span>      List&lt;IOException&gt; ioes = new ArrayList&lt;&gt;();<a name="line.6210"></a>
+<span class="sourceLineNo">6211</span>      List&lt;Pair&lt;byte[], String&gt;&gt; failures = new ArrayList&lt;&gt;();<a name="line.6211"></a>
+<span class="sourceLineNo">6212</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6212"></a>
+<span class="sourceLineNo">6213</span>        byte[] familyName = p.getFirst();<a name="line.6213"></a>
+<span class="sourceLineNo">6214</span>        String path = p.getSecond();<a name="line.6214"></a>
+<span class="sourceLineNo">6215</span><a name="line.6215"></a>
+<span class="sourceLineNo">6216</span>        HStore store = getStore(familyName);<a name="line.6216"></a>
+<span class="sourceLineNo">6217</span>        if (store == null) {<a name="line.6217"></a>
+<span class="sourceLineNo">6218</span>          IOException ioe = new org.apache.hadoop.hbase.DoNotRetryIOException(<a name="line.6218"></a>
+<span class="sourceLineNo">6219</span>              "No such column family " + Bytes.toStringBinary(familyName));<a name="line.6219"></a>
+<span class="sourceLineNo">6220</span>          ioes.add(ioe);<a name="line.6220"></a>
+<span class="sourceLineNo">6221</span>        } else {<a name="line.6221"></a>
+<span class="sourceLineNo">6222</span>          try {<a name="line.6222"></a>
+<span class="sourceLineNo">6223</span>            store.assertBulkLoadHFileOk(new Path(path));<a name="line.6223"></a>
+<span class="sourceLineNo">6224</span>          } catch (WrongRegionException wre) {<a name="line.6224"></a>
+<span class="sourceLineNo">6225</span>            // recoverable (file doesn't fit in region)<a name="line.6225"></a>
+<span class="sourceLineNo">6226</span>            failures.add(p);<a name="line.6226"></a>
+<span class="sourceLineNo">6227</span>          } catch (IOException ioe) {<a name="line.6227"></a>
+<span class="sourceLineNo">6228</span>            // unrecoverable (hdfs problem)<a name="line.6228"></a>
+<span class="sourceLineNo">6229</span>            ioes.add(ioe);<a name="line.6229"></a>
+<span class="sourceLineNo">6230</span>          }<a name="line.6230"></a>
+<span class="sourceLineNo">6231</span>        }<a name="line.6231"></a>
+<span class="sourceLineNo">6232</span>      }<a name="line.6232"></a>
+<span class="sourceLineNo">6233</span><a name="line.6233"></a>
+<span class="sourceLineNo">6234</span>      // validation failed because of some sort of IO problem.<a name="line.6234"></a>
+<span class="sourceLineNo">6235</span>      if (ioes.size() != 0) {<a name="line.6235"></a>
+<span class="sourceLineNo">6236</span>        IOException e = MultipleIOException.createIOException(ioes);<a name="line.6236"></a>
+<span class="sourceLineNo">6237</span>        LOG.error("There were one or more IO errors when checking if the bulk load is ok.", e);<a name="line.6237"></a>
+<span class="sourceLineNo">6238</span>        throw e;<a name="line.6238"></a>
+<span class="sourceLineNo">6239</span>      }<a name="line.6239"></a>
+<span class="sourceLineNo">6240</span><a name="line.6240"></a>
+<span class="sourceLineNo">6241</span>      // validation failed, bail out before doing anything permanent.<a name="line.6241"></a>
+<span class="sourceLineNo">6242</span>      if (failures.size() != 0) {<a name="line.6242"></a>
+<span class="sourceLineNo">6243</span>        StringBuilder list = new StringBuilder();<a name="line.6243"></a>
+<span class="sourceLineNo">6244</span>        for (Pair&lt;byte[], String&gt; p : failures) {<a name="line.6244"></a>
+<span class="sourceLineNo">6245</span>          list.append("\n").append(Bytes.toString(p.getFirst())).append(" : ")<a name="line.6245"></a>
+<span class="sourceLineNo">6246</span>              .append(p.getSecond());<a name="line.6246"></a>
+<span class="sourceLineNo">6247</span>        }<a name="line.6247"></a>
+<span class="sourceLineNo">6248</span>        // problem when validating<a name="line.6248"></a>
+<span class="sourceLineNo">6249</span>        LOG.warn("There was a recoverable bulk load failure likely due to a" +<a name="line.6249"></a>
+<span class="sourceLineNo">6250</span>            " split.  These (family, HFile) pairs were not loaded: " + list);<a name="line.6250"></a>
+<span class="sourceLineNo">6251</span>        return null;<a name="line.6251"></a>
+<span class="sourceLineNo">6252</span>      }<a name="line.6252"></a>
+<span class="sourceLineNo">6253</span><a name="line.6253"></a>
+<span class="sourceLineNo">6254</span>      // We need to assign a sequential ID that's in between two memstores in order to preserve<a name="line.6254"></a>
+<span class="sourceLineNo">6255</span>      // the guarantee that all the edits lower than the highest sequential ID from all the<a name="line.6255"></a>
+<span class="sourceLineNo">6256</span>      // HFiles are flushed on disk. See HBASE-10958.  The sequence id returned when we flush is<a name="line.6256"></a>
+<span class="sourceLineNo">6257</span>      // guaranteed to be one beyond the file made when we flushed (or if nothing to flush, it is<a name="line.6257"></a>
+<span class="sourceLineNo">6258</span>      // a sequence id that we can be sure is beyond the last hfile written).<a name="line.6258"></a>
+<span class="sourceLineNo">6259</span>      if (assignSeqId) {<a name="line.6259"></a>
+<span class="sourceLineNo">6260</span>        FlushResult fs = flushcache(true, false, FlushLifeCycleTracker.DUMMY);<a name="line.6260"></a>
+<span class="sourceLineNo">6261</span>        if (fs.isFlushSucceeded()) {<a name="line.6261"></a>
+<span class="sourceLineNo">6262</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6262"></a>
+<span class="sourceLineNo">6263</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY) {<a name="line.6263"></a>
+<span class="sourceLineNo">6264</span>          seqId = ((FlushResultImpl)fs).flushSequenceId;<a name="line.6264"></a>
+<span class="sourceLineNo">6265</span>        } else if (fs.getResult() == FlushResult.Result.CANNOT_FLUSH) {<a name="line.6265"></a>
+<span class="sourceLineNo">6266</span>          // CANNOT_FLUSH may mean that a flush is already on-going<a name="line.6266"></a>
+<span class="sourceLineNo">6267</span>          // we need to wait for that flush to complete<a name="line.6267"></a>
+<span class="sourceLineNo">6268</span>          waitForFlushes();<a name="line.6268"></a>
+<span class="sourceLineNo">6269</span>        } else {<a name="line.6269"></a>
+<span class="sourceLineNo">6270</span>          throw new IOException("Could not bulk load with an assigned sequential ID because the "+<a name="line.6270"></a>
+<span class="sourceLineNo">6271</span>            "flush didn't run. Reason for not flushing: " + ((FlushResultImpl)fs).failureReason);<a name="line.6271"></a>
+<span class="sourceLineNo">6272</span>        }<a name="line.6272"></a>
+<span class="sourceLineNo">6273</span>      }<a name="line.6273"></a>
+<span class="sourceLineNo">6274</span><a name="line.6274"></a>
+<span class="sourceLineNo">6275</span>      Map&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; familyWithFinalPath =<a name="line.6275"></a>
+<span class="sourceLineNo">6276</span>          new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);<a name="line.6276"></a>
+<span class="sourceLineNo">6277</span>      for (Pair&lt;byte[], String&gt; p : familyPaths) {<a name="line.6277"></a>
+<span class="sourceLineNo">6278</span>        byte[] familyName = p.getFirst();<a name="line.6278"></a>
+<span class="sourceLineNo">6279</span>        String path = p.getSecond();<a name="line.6279"></a>
+<span class="sourceLineNo">6280</span>        HStore store = getStore(familyName);<a name="line.6280"></a>
+<span class="sourceLineNo">6281</span>        if (!familyWithFinalPath.containsKey(familyName)) {<a name="line.6281"></a>
+<span class="sourceLineNo">6282</span>          familyWithFinalPath.put(familyName, new ArrayList&lt;&gt;());<a name="line.6282"></a>
+<span class="sourceLineNo">6283</span>        }<a name="line.6283"></a>
+<span class="sourceLineNo">6284</span>        List&lt;Pair&lt;Path, Path&gt;&gt; lst = familyWithFinalPath.get(familyName);<a name="line.6284"></a>
+<span class="sourceLineNo">6285</span>        try {<a name="line.6285"></a>
+<span class="sourceLineNo">6286</span>          String finalPath = path;<a name="line.6286"></a>
+<span class="sourceLineNo">6287</span>          if (bulkLoadListener != null) {<a name="line.6287"></a>
+<span class="sourceLineNo">6288</span>            finalPath = bulkLoadListener.prepareBulkLoad(familyName, path, copyFile);<a name="line.6288"></a>
+<span class="sourceLineNo">6289</span>          }<a name="line.6289"></a>
+<span class="sourceLineNo">6290</span>          Pair&lt;Path, Path&gt; pair = store.preBulkLoadHFile(finalPath, seqId);<a name="line.6290"></a>
+<span class="sourceLineNo">6291</span>          lst.add(pair);<a name="line.6291"></a>
+<span class="sourceLineNo">6292</span>        } catch (IOException ioe) {<a name="line.6292"></a>
+<span class="sourceLineNo">6293</span>          // A failure here can cause an atomicity violation that we currently<a name="line.6293"></a>
+<span class="sourceLineNo">6294</span>          // cannot recover from since it is likely a failed HDFS operation.<a name="line.6294"></a>
+<span class="sourceLineNo">6295</span><a name="line.6295"></a>
+<span class="sourceLineNo">6296</span>          LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6296"></a>
+<span class="sourceLineNo">6297</span>              " load " + Bytes.toString(p.getFirst()) + " : " + p.getSecond(), ioe);<a name="line.6297"></a>
+<span class="sourceLineNo">6298</span>          if (bulkLoadListener != null) {<a name="line.6298"></a>
+<span class="sourceLineNo">6299</span>            try {<a name="line.6299"></a>
+<span class="sourceLineNo">6300</span>              bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6300"></a>
+<span class="sourceLineNo">6301</span>            } catch (Exception ex) {<a name="line.6301"></a>
+<span class="sourceLineNo">6302</span>              LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6302"></a>
+<span class="sourceLineNo">6303</span>                  Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6303"></a>
+<span class="sourceLineNo">6304</span>            }<a name="line.6304"></a>
+<span class="sourceLineNo">6305</span>          }<a name="line.6305"></a>
+<span class="sourceLineNo">6306</span>          throw ioe;<a name="line.6306"></a>
+<span class="sourceLineNo">6307</span>        }<a name="line.6307"></a>
+<span class="sourceLineNo">6308</span>      }<a name="line.6308"></a>
+<span class="sourceLineNo">6309</span><a name="line.6309"></a>
+<span class="sourceLineNo">6310</span>      if (this.getCoprocessorHost() != null) {<a name="line.6310"></a>
+<span class="sourceLineNo">6311</span>        for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6311"></a>
+<span class="sourceLineNo">6312</span>          this.getCoprocessorHost().preCommitStoreFile(entry.getKey(), entry.getValue());<a name="line.6312"></a>
+<span class="sourceLineNo">6313</span>        }<a name="line.6313"></a>
+<span class="sourceLineNo">6314</span>      }<a name="line.6314"></a>
+<span class="sourceLineNo">6315</span>      for (Map.Entry&lt;byte[], List&lt;Pair&lt;Path, Path&gt;&gt;&gt; entry : familyWithFinalPath.entrySet()) {<a name="line.6315"></a>
+<span class="sourceLineNo">6316</span>        byte[] familyName = entry.getKey();<a name="line.6316"></a>
+<span class="sourceLineNo">6317</span>        for (Pair&lt;Path, Path&gt; p : entry.getValue()) {<a name="line.6317"></a>
+<span class="sourceLineNo">6318</span>          String path = p.getFirst().toString();<a name="line.6318"></a>
+<span class="sourceLineNo">6319</span>          Path commitedStoreFile = p.getSecond();<a name="line.6319"></a>
+<span class="sourceLineNo">6320</span>          HStore store = getStore(familyName);<a name="line.6320"></a>
+<span class="sourceLineNo">6321</span>          try {<a name="line.6321"></a>
+<span class="sourceLineNo">6322</span>            store.bulkLoadHFile(familyName, path, commitedStoreFile);<a name="line.6322"></a>
+<span class="sourceLineNo">6323</span>            // Note the size of the store file<a name="line.6323"></a>
+<span class="sourceLineNo">6324</span>            try {<a name="line.6324"></a>
+<span class="sourceLineNo">6325</span>              FileSystem fs = commitedStoreFile.getFileSystem(baseConf);<a name="line.6325"></a>
+<span class="sourceLineNo">6326</span>              storeFilesSizes.put(commitedStoreFile.getName(), fs.getFileStatus(commitedStoreFile)<a name="line.6326"></a>
+<span class="sourceLineNo">6327</span>                  .getLen());<a name="line.6327"></a>
+<span class="sourceLineNo">6328</span>            } catch (IOException e) {<a name="line.6328"></a>
+<span class="sourceLineNo">6329</span>              LOG.warn("Failed to find the size of hfile " + commitedStoreFile, e);<a name="line.6329"></a>
+<span class="sourceLineNo">6330</span>              storeFilesSizes.put(commitedStoreFile.getName(), 0L);<a name="line.6330"></a>
+<span class="sourceLineNo">6331</span>            }<a name="line.6331"></a>
+<span class="sourceLineNo">6332</span><a name="line.6332"></a>
+<span class="sourceLineNo">6333</span>            if(storeFiles.containsKey(familyName)) {<a name="line.6333"></a>
+<span class="sourceLineNo">6334</span>              storeFiles.get(familyName).add(commitedStoreFile);<a name="line.6334"></a>
+<span class="sourceLineNo">6335</span>            } else {<a name="line.6335"></a>
+<span class="sourceLineNo">6336</span>              List&lt;Path&gt; storeFileNames = new ArrayList&lt;&gt;();<a name="line.6336"></a>
+<span class="sourceLineNo">6337</span>              storeFileNames.add(commitedStoreFile);<a name="line.6337"></a>
+<span class="sourceLineNo">6338</span>              storeFiles.put(familyName, storeFileNames);<a name="line.6338"></a>
 <span class="sourceLineNo">6339</span>            }<a name="line.6339"></a>
-<span class="sourceLineNo">6340</span>          } catch (IOException ioe) {<a name="line.6340"></a>
-<span class="sourceLineNo">6341</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6341"></a>
-<span class="sourceLineNo">6342</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6342"></a>
-<span class="sourceLineNo">6343</span><a name="line.6343"></a>
-<span class="sourceLineNo">6344</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6344"></a>
-<span class="sourceLineNo">6345</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6345"></a>
-<span class="sourceLineNo">6346</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6346"></a>
-<span class="sourceLineNo">6347</span>            if (bulkLoadListener != null) {<a name="line.6347"></a>
-<span class="sourceLineNo">6348</span>              try {<a name="line.6348"></a>
-<span class="sourceLineNo">6349</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6349"></a>
-<span class="sourceLineNo">6350</span>              } catch (Exception ex) {<a name="line.6350"></a>
-<span class="sourceLineNo">6351</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6351"></a>
-<span class="sourceLineNo">6352</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6352"></a>
-<span class="sourceLineNo">6353</span>              }<a name="line.6353"></a>
-<span class="sourceLineNo">6354</span>            }<a name="line.6354"></a>
-<span class="sourceLineNo">6355</span>            throw ioe;<a name="line.6355"></a>
-<span class="sourceLineNo">6356</span>          }<a name="line.6356"></a>
-<span class="sourceLineNo">6357</span>        }<a name="line.6357"></a>
-<span class="sourceLineNo">6358</span>      }<a name="line.6358"></a>
-<span class="sourceLineNo">6359</span><a name="line.6359"></a>
-<span class="sourceLineNo">6360</span>      isSuccessful = true;<a name="line.6360"></a>
-<span class="sourceLineNo">6361</span>    } finally {<a name="line.6361"></a>
-<span class="sourceLineNo">6362</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6362"></a>
-<span class="sourceLineNo">6363</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6363"></a>
-<span class="sourceLineNo">6364</span>        try {<a name="line.6364"></a>
-<span class="sourceLineNo">6365</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6365"></a>
-<span class="sourceLineNo">6366</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6366"></a>
-<span class="sourceLineNo">6367</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6367"></a>
-<span class="sourceLineNo">6368</span>                  storeFiles,<a name="line.6368"></a>
-<span class="sourceLineNo">6369</span>                storeFilesSizes, seqId);<a name="line.6369"></a>
-<span class="sourceLineNo">6370</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6370"></a>
-<span class="sourceLineNo">6371</span>              loadDescriptor, mvcc);<a name="line.6371"></a>
-<span class="sourceLineNo">6372</span>        } catch (IOException ioe) {<a name="line.6372"></a>
-<span class="sourceLineNo">6373</span>          if (this.rsServices != null) {<a name="line.6373"></a>
-<span class="sourceLineNo">6374</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6374"></a>
-<span class="sourceLineNo">6375</span>            // the event into WAL<a name="line.6375"></a>
-<span class="sourceLineNo">6376</span>            isSuccessful = false;<a name="line.6376"></a>
-<span class="sourceLineNo">6377</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6377"></a>
-<span class="sourceLineNo">6378</span>          }<a name="line.6378"></a>
-<span class="sourceLineNo">6379</span>        }<a name="line.6379"></a>
-<span class="sourceLineNo">6380</span>      }<a name="line.6380"></a>
-<span class="sourceLineNo">6381</span><a name="line.6381"></a>
-<span class="sourceLineNo">6382</span>      closeBulkRegionOperation();<a name="line.6382"></a>
-<span class="sourceLineNo">6383</span>    }<a name="line.6383"></a>
-<span class="sourceLineNo">6384</span>    return isSuccessful ? storeFiles : null;<a name="line.6384"></a>
-<span class="sourceLineNo">6385</span>  }<a name="line.6385"></a>
-<span class="sourceLineNo">6386</span><a name="line.6386"></a>
-<span class="sourceLineNo">6387</span>  @Override<a name="line.6387"></a>
-<span class="sourceLineNo">6388</span>  public boolean equals(Object o) {<a name="line.6388"></a>
-<span class="sourceLineNo">6389</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6389"></a>
-<span class="sourceLineNo">6390</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6390"></a>
-<span class="sourceLineNo">6391</span>  }<a name="line.6391"></a>
-<span class="sourceLineNo">6392</span><a name="line.6392"></a>
-<span class="sourceLineNo">6393</span>  @Override<a name="line.6393"></a>
-<span class="sourceLineNo">6394</span>  public int hashCode() {<a name="line.6394"></a>
-<span class="sourceLineNo">6395</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6395"></a>
-<span class="sourceLineNo">6396</span>  }<a name="line.6396"></a>
-<span class="sourceLineNo">6397</span><a name="line.6397"></a>
-<span class="sourceLineNo">6398</span>  @Override<a name="line.6398"></a>
-<span class="sourceLineNo">6399</span>  public String toString() {<a name="line.6399"></a>
-<span class="sourceLineNo">6400</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6400"></a>
-<span class="sourceLineNo">6401</span>  }<a name="line.6401"></a>
-<span class="sourceLineNo">6402</span><a name="line.6402"></a>
-<span class="sourceLineNo">6403</span>  /**<a name="line.6403"></a>
-<span class="sourceLineNo">6404</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6404"></a>
-<span class="sourceLineNo">6405</span>   */<a name="line.6405"></a>
-<span class="sourceLineNo">6406</span>  class RegionScannerImpl<a name="line.6406"></a>
-<span class="sourceLineNo">6407</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6407"></a>
-<span class="sourceLineNo">6408</span>    // Package local for testability<a name="line.6408"></a>
-<span class="sourceLineNo">6409</span>    KeyValueHeap storeHeap = null;<a name="line.6409"></a>
-<span class="sourceLineNo">6410</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6410"></a>
-<span class="sourceLineNo">6411</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6411"></a>
-<span class="sourceLineNo">6412</span>    KeyValueHeap joinedHeap = null;<a name="line.6412"></a>
-<span class="sourceLineNo">6413</span>    /**<a name="line.6413"></a>
-<span class="sourceLineNo">6414</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6414"></a>
-<span class="sourceLineNo">6415</span>     * contain the row for which we are populating the values.*/<a name="line.6415"></a>
-<span class="sourceLineNo">6416</span>    protected Cell joinedContinuationRow = null;<a name="line.6416"></a>
-<span class="sourceLineNo">6417</span>    private boolean filterClosed = false;<a name="line.6417"></a>
-<span class="sourceLineNo">6418</span><a name="line.6418"></a>
-<span class="sourceLineNo">6419</span>    protected final byte[] stopRow;<a name="line.6419"></a>
-<span class="sourceLineNo">6420</span>    protected final boolean includeStopRow;<a name="line.6420"></a>
-<span class="sourceLineNo">6421</span>    protected final HRegion region;<a name="line.6421"></a>
-<span class="sourceLineNo">6422</span>    protected final CellComparator comparator;<a name="line.6422"></a>
-<span class="sourceLineNo">6423</span><a name="line.6423"></a>
-<span class="sourceLineNo">6424</span>    private final long readPt;<a name="line.6424"></a>
-<span class="sourceLineNo">6425</span>    private final long maxResultSize;<a name="line.6425"></a>
-<span class="sourceLineNo">6426</span>    private final ScannerContext defaultScannerContext;<a name="line.6426"></a>
-<span class="sourceLineNo">6427</span>    private final FilterWrapper filter;<a name="line.6427"></a>
-<span class="sourceLineNo">6428</span><a name="line.6428"></a>
-<span class="sourceLineNo">6429</span>    @Override<a name="line.6429"></a>
-<span class="sourceLineNo">6430</span>    public RegionInfo getRegionInfo() {<a name="line.6430"></a>
-<span class="sourceLineNo">6431</span>      return region.getRegionInfo();<a name="line.6431"></a>
-<span class="sourceLineNo">6432</span>    }<a name="line.6432"></a>
-<span class="sourceLineNo">6433</span><a name="line.6433"></a>
-<span class="sourceLineNo">6434</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6434"></a>
-<span class="sourceLineNo">6435</span>        throws IOException {<a name="line.6435"></a>
-<span class="sourceLineNo">6436</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6436"></a>
-<span class="sourceLineNo">6437</span>    }<a name="line.6437"></a>
-<span class="sourceLineNo">6438</span><a name="line.6438"></a>
-<span class="sourceLineNo">6439</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6439"></a>
-<span class="sourceLineNo">6440</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6440"></a>
-<span class="sourceLineNo">6441</span>      this.region = region;<a name="line.6441"></a>
-<span class="sourceLineNo">6442</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6442"></a>
-<span class="sourceLineNo">6443</span>      if (scan.hasFilter()) {<a name="line.6443"></a>
-<span class="sourceLineNo">6444</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6444"></a>
-<span class="sourceLineNo">6445</span>      } else {<a name="line.6445"></a>
-<span class="sourceLineNo">6446</span>        this.filter = null;<a name="line.6446"></a>
-<span class="sourceLineNo">6447</span>      }<a name="line.6447"></a>
-<span class="sourceLineNo">6448</span>      this.comparator = region.getCellComparator();<a name="line.6448"></a>
-<span class="sourceLineNo">6449</span>      /**<a name="line.6449"></a>
-<span class="sourceLineNo">6450</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6450"></a>
-<span class="sourceLineNo">6451</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6451"></a>
-<span class="sourceLineNo">6452</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6452"></a>
-<span class="sourceLineNo">6453</span>       */<a name="line.6453"></a>
-<span class="sourceLineNo">6454</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6454"></a>
-<span class="sourceLineNo">6455</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6455"></a>
-<span class="sourceLineNo">6456</span>      this.stopRow = scan.getStopRow();<a name="line.6456"></a>
-<span class="sourceLineNo">6457</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6457"></a>
-<span class="sourceLineNo">6458</span><a name="line.6458"></a>
-<span class="sourceLineNo">6459</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6459"></a>
-<span class="sourceLineNo">6460</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6460"></a>
-<span class="sourceLineNo">6461</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6461"></a>
-<span class="sourceLineNo">6462</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6462"></a>
-<span class="sourceLineNo">6463</span>      synchronized (scannerReadPoints) {<a name="line.6463"></a>
-<span class="sourceLineNo">6464</span>        if (mvccReadPoint &gt; 0) {<a name="line.6464"></a>
-<span class="sourceLineNo">6465</span>          this.readPt = mvccReadPoint;<a name="line.6465"></a>
-<span class="sourceLineNo">6466</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6466"></a>
-<span class="sourceLineNo">6467</span>            || rsServices.getNonceManager() == null) {<a name="line.6467"></a>
-<span class="sourceLineNo">6468</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6468"></a>
-<span class="sourceLineNo">6469</span>        } else {<a name="line.6469"></a>
-<span class="sourceLineNo">6470</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6470"></a>
-<span class="sourceLineNo">6471</span>        }<a name="line.6471"></a>
-<span class="sourceLineNo">6472</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6472"></a>
-<span class="sourceLineNo">6473</span>      }<a name="line.6473"></a>
-<span class="sourceLineNo">6474</span>      initializeScanners(scan, additionalScanners);<a name="line.6474"></a>
-<span class="sourceLineNo">6475</span>    }<a name="line.6475"></a>
-<span class="sourceLineNo">6476</span><a name="line.6476"></a>
-<span class="sourceLineNo">6477</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6477"></a>
-<span class="sourceLineNo">6478</span>        throws IOException {<a name="line.6478"></a>
-<span class="sourceLineNo">6479</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6479"></a>
-<span class="sourceLineNo">6480</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6480"></a>
-<span class="sourceLineNo">6481</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6481"></a>
-<span class="sourceLineNo">6482</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6482"></a>
-<span class="sourceLineNo">6483</span>      // Store all already instantiated scanners for exception handling<a name="line.6483"></a>
-<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6484"></a>
-<span class="sourceLineNo">6485</span>      // handle additionalScanners<a name="line.6485"></a>
-<span class="sourceLineNo">6486</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6486"></a>
-<span class="sourceLineNo">6487</span>        scanners.addAll(additionalScanners);<a name="line.6487"></a>
-<span class="sourceLineNo">6488</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6488"></a>
-<span class="sourceLineNo">6489</span>      }<a name="line.6489"></a>
-<span class="sourceLineNo">6490</span><a name="line.6490"></a>
-<span class="sourceLineNo">6491</span>      try {<a name="line.6491"></a>
-<span class="sourceLineNo">6492</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6492"></a>
-<span class="sourceLineNo">6493</span>          HStore store = stores.get(entry.getKey());<a name="line.6493"></a>
-<span class="sourceLineNo">6494</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6494"></a>
-<span class="sourceLineNo">6495</span>          instantiatedScanners.add(scanner);<a name="line.6495"></a>
-<span class="sourceLineNo">6496</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6496"></a>
-<span class="sourceLineNo">6497</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6497"></a>
-<span class="sourceLineNo">6498</span>            scanners.add(scanner);<a name="line.6498"></a>
-<span class="sourceLineNo">6499</span>          } else {<a name="line.6499"></a>
-<span class="sourceLineNo">6500</span>            joinedScanners.add(scanner);<a name="line.6500"></a>
-<span class="sourceLineNo">6501</span>          }<a name="line.6501"></a>
-<span class="sourceLineNo">6502</span>        }<a name="line.6502"></a>
-<span class="sourceLineNo">6503</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6503"></a>
-<span class="sourceLineNo">6504</span>      } catch (Throwable t) {<a name="line.6504"></a>
-<span class="sourceLineNo">6505</span>        throw handleException(instantiatedScanners, t);<a name="line.6505"></a>
-<span class="sourceLineNo">6506</span>      }<a name="line.6506"></a>
-<span class="sourceLineNo">6507</span>    }<a name="line.6507"></a>
-<span class="sourceLineNo">6508</span><a name="line.6508"></a>
-<span class="sourceLineNo">6509</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6509"></a>
-<span class="sourceLineNo">6510</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6510"></a>
-<span class="sourceLineNo">6511</span>        throws IOException {<a name="line.6511"></a>
-<span class="sourceLineNo">6512</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6512"></a>
-<span class="sourceLineNo">6513</span>      if (!joinedScanners.isEmpty()) {<a name="line.6513"></a>
-<span class="sourceLineNo">6514</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6514"></a>
-<span class="sourceLineNo">6515</span>      }<a name="line.6515"></a>
-<span class="sourceLineNo">6516</span>    }<a name="line.6516"></a>
-<span class="sourceLineNo">6517</span><a name="line.6517"></a>
-<span class="sourceLineNo">6518</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6518"></a>
-<span class="sourceLineNo">6519</span>        Throwable t) {<a name="line.6519"></a>
-<span class="sourceLineNo">6520</span>      // remove scaner read point before throw the exception<a name="line.6520"></a>
-<span class="sourceLineNo">6521</span>      scannerReadPoints.remove(this);<a name="line.6521"></a>
-<span class="sourceLineNo">6522</span>      if (storeHeap != null) {<a name="line.6522"></a>
-<span class="sourceLineNo">6523</span>        storeHeap.close();<a name="line.6523"></a>
-<span class="sourceLineNo">6524</span>        storeHeap = null;<a name="line.6524"></a>
-<span class="sourceLineNo">6525</span>        if (joinedHeap != null) {<a name="line.6525"></a>
-<span class="sourceLineNo">6526</span>          joinedHeap.close();<a name="line.6526"></a>
-<span class="sourceLineNo">6527</span>          joinedHeap = null;<a name="line.6527"></a>
-<span class="sourceLineNo">6528</span>        }<a name="line.6528"></a>
-<span class="sourceLineNo">6529</span>      } else {<a name="line.6529"></a>
-<span class="sourceLineNo">6530</span>        // close all already instantiated scanners before throwing the exception<a name="line.6530"></a>
-<span class="sourceLineNo">6531</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6531"></a>
-<span class="sourceLineNo">6532</span>          scanner.close();<a name="line.6532"></a>
-<span class="sourceLineNo">6533</span>        }<a name="line.6533"></a>
-<span class="sourceLineNo">6534</span>      }<a name="line.6534"></a>
-<span class="sourceLineNo">6535</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6535"></a>
-<span class="sourceLineNo">6536</span>    }<a name="line.6536"></a>
-<span class="sourceLineNo">6537</span><a name="line.6537"></a>
-<span class="sourceLineNo">6538</span>    @Override<a name="line.6538"></a>
-<span class="sourceLineNo">6539</span>    public long getMaxResultSize() {<a name="line.6539"></a>
-<span class="sourceLineNo">6540</span>      return maxResultSize;<a name="line.6540"></a>
-<span class="sourceLineNo">6541</span>    }<a name="line.6541"></a>
-<span class="sourceLineNo">6542</span><a name="line.6542"></a>
-<span class="sourceLineNo">6543</span>    @Override<a name="line.6543"></a>
-<span class="sourceLineNo">6544</span>    public long getMvccReadPoint() {<a name="line.6544"></a>
-<span class="sourceLineNo">6545</span>      return this.readPt;<a name="line.6545"></a>
-<span class="sourceLineNo">6546</span>    }<a name="line.6546"></a>
-<span class="sourceLineNo">6547</span><a name="line.6547"></a>
-<span class="sourceLineNo">6548</span>    @Override<a name="line.6548"></a>
-<span class="sourceLineNo">6549</span>    public int getBatch() {<a name="line.6549"></a>
-<span class="sourceLineNo">6550</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6550"></a>
-<span class="sourceLineNo">6551</span>    }<a name="line.6551"></a>
-<span class="sourceLineNo">6552</span><a name="line.6552"></a>
-<span class="sourceLineNo">6553</span>    /**<a name="line.6553"></a>
-<span class="sourceLineNo">6554</span>     * Reset both the filter and the old filter.<a name="line.6554"></a>
-<span class="sourceLineNo">6555</span>     *<a name="line.6555"></a>
-<span class="sourceLineNo">6556</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6556"></a>
-<span class="sourceLineNo">6557</span>     */<a name="line.6557"></a>
-<span class="sourceLineNo">6558</span>    protected void resetFilters() throws IOException {<a name="line.6558"></a>
-<span class="sourceLineNo">6559</span>      if (filter != null) {<a name="line.6559"></a>
-<span class="sourceLineNo">6560</span>        filter.reset();<a name="line.6560"></a>
-<span class="sourceLineNo">6561</span>      }<a name="line.6561"></a>
-<span class="sourceLineNo">6562</span>    }<a name="line.6562"></a>
-<span class="sourceLineNo">6563</span><a name="line.6563"></a>
-<span class="sourceLineNo">6564</span>    @Override<a name="line.6564"></a>
-<span class="sourceLineNo">6565</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6565"></a>
-<span class="sourceLineNo">6566</span>        throws IOException {<a name="line.6566"></a>
-<span class="sourceLineNo">6567</span>      // apply the batching limit by default<a name="line.6567"></a>
-<span class="sourceLineNo">6568</span>      return next(outResults, defaultScannerContext);<a name="line.6568"></a>
-<span class="sourceLineNo">6569</span>    }<a name="line.6569"></a>
-<span class="sourceLineNo">6570</span><a name="line.6570"></a>
-<span class="sourceLineNo">6571</span>    @Override<a name="line.6571"></a>
-<span class="sourceLineNo">6572</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6572"></a>
-<span class="sourceLineNo">6573</span>    throws IOException {<a name="line.6573"></a>
-<span class="sourceLineNo">6574</span>      if (this.filterClosed) {<a name="line.6574"></a>
-<span class="sourceLineNo">6575</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6575"></a>
-<span class="sourceLineNo">6576</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6576"></a>
-<span class="sourceLineNo">6577</span>            "or a lengthy garbage collection");<a name="line.6577"></a>
-<span class="sourceLineNo">6578</span>      }<a name="line.6578"></a>
-<span class="sourceLineNo">6579</span>      startRegionOperation(Operation.SCAN);<a name="line.6579"></a>
-<span class="sourceLineNo">6580</span>      try {<a name="line.6580"></a>
-<span class="sourceLineNo">6581</span>        return nextRaw(outResults, scannerContext);<a name="line.6581"></a>
-<span class="sourceLineNo">6582</span>      } finally {<a name="line.6582"></a>
-<span class="sourceLineNo">6583</span>        closeRegionOperation(Operation.SCAN);<a name="line.6583"></a>
-<span class="sourceLineNo">6584</span>      }<a name="line.6584"></a>
-<span class="sourceLineNo">6585</span>    }<a name="line.6585"></a>
-<span class="sourceLineNo">6586</span><a name="line.6586"></a>
-<span class="sourceLineNo">6587</span>    @Override<a name="line.6587"></a>
-<span class="sourceLineNo">6588</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6588"></a>
-<span class="sourceLineNo">6589</span>      // Use the RegionScanner's context by default<a name="line.6589"></a>
-<span class="sourceLineNo">6590</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6590"></a>
-<span class="sourceLineNo">6591</span>    }<a name="line.6591"></a>
-<span class="sourceLineNo">6592</span><a name="line.6592"></a>
-<span class="sourceLineNo">6593</span>    @Override<a name="line.6593"></a>
-<span class="sourceLineNo">6594</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6594"></a>
-<span class="sourceLineNo">6595</span>        throws IOException {<a name="line.6595"></a>
-<span class="sourceLineNo">6596</span>      if (storeHeap == null) {<a name="line.6596"></a>
-<span class="sourceLineNo">6597</span>        // scanner is closed<a name="line.6597"></a>
-<span class="sourceLineNo">6598</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6598"></a>
-<span class="sourceLineNo">6599</span>      }<a name="line.6599"></a>
-<span class="sourceLineNo">6600</span>      boolean moreValues = false;<a name="line.6600"></a>
-<span class="sourceLineNo">6601</span>      if (outResults.isEmpty()) {<a name="line.6601"></a>
-<span class="sourceLineNo">6602</span>        // Usually outResults is empty. This is true when next is called<a name="line.6602"></a>
-<span class="sourceLineNo">6603</span>        // to handle scan or get operation.<a name="line.6603"></a>
-<span class="sourceLineNo">6604</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6604"></a>
-<span class="sourceLineNo">6605</span>      } else {<a name="line.6605"></a>
-<span class="sourceLineNo">6606</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6606"></a>
-<span class="sourceLineNo">6607</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6607"></a>
-<span class="sourceLineNo">6608</span>        outResults.addAll(tmpList);<a name="line.6608"></a>
-<span class="sourceLineNo">6609</span>      }<a name="line.6609"></a>
-<span class="sourceLineNo">6610</span><a name="line.6610"></a>
-<span class="sourceLineNo">6611</span>      if (!outResults.isEmpty()) {<a name="line.6611"></a>
-<span class="sourceLineNo">6612</span>        readRequestsCount.increment();<a name="line.6612"></a>
-<span class="sourceLineNo">6613</span>      }<a name="line.6613"></a>
-<span class="sourceLineNo">6614</span><a name="line.6614"></a>
-<span class="sourceLineNo">6615</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6615"></a>
-<span class="sourceLineNo">6616</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6616"></a>
-<span class="sourceLineNo">6617</span>      // between rows<a name="line.6617"></a>
-<span class="sourceLineNo">6618</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6618"></a>
-<span class="sourceLineNo">6619</span>        resetFilters();<a name="line.6619"></a>
-<span class="sourceLineNo">6620</span>      }<a name="line.6620"></a>
-<span class="sourceLineNo">6621</span><a name="line.6621"></a>
-<span class="sourceLineNo">6622</span>      if (isFilterDoneInternal()) {<a name="line.6622"></a>
-<span class="sourceLineNo">6623</span>        moreValues = false;<a name="line.6623"></a>
-<span class="sourceLineNo">6624</span>      }<a name="line.6624"></a>
-<span class="sourceLineNo">6625</span>      return moreValues;<a name="line.6625"></a>
-<span class="sourceLineNo">6626</span>    }<a name="line.6626"></a>
-<span class="sourceLineNo">6627</span><a name="line.6627"></a>
-<span class="sourceLineNo">6628</span>    /**<a name="line.6628"></a>
-<span class="sourceLineNo">6629</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6629"></a>
-<span class="sourceLineNo">6630</span>     */<a name="line.6630"></a>
-<span class="sourceLineNo">6631</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6631"></a>
-<span class="sourceLineNo">6632</span>            throws IOException {<a name="line.6632"></a>
-<span class="sourceLineNo">6633</span>      assert joinedContinuationRow != null;<a name="line.6633"></a>
-<span class="sourceLineNo">6634</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6634"></a>
-<span class="sourceLineNo">6635</span>          joinedContinuationRow);<a name="line.6635"></a>
-<span class="sourceLineNo">6636</span><a name="line.6636"></a>
-<span class="sourceLineNo">6637</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6637"></a>
-<span class="sourceLineNo">6638</span>        // We are done with this row, reset the continuation.<a name="line.6638"></a>
-<span class="sourceLineNo">6639</span>        joinedContinuationRow = null;<a name="line.6639"></a>
-<span class="sourceLineNo">6640</span>      }<a name="line.6640"></a>
-<span class="sourceLineNo">6641</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6641"></a>
-<span class="sourceLineNo">6642</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6642"></a>
-<span class="sourceLineNo">6643</span>      sort(results, comparator);<a name="line.6643"></a>
-<span class="sourceLineNo">6644</span>      return moreValues;<a name="line.6644"></a>
-<span class="sourceLineNo">6645</span>    }<a name="line.6645"></a>
-<span class="sourceLineNo">6646</span><a name="line.6646"></a>
-<span class="sourceLineNo">6647</span>    /**<a name="line.6647"></a>
-<span class="sourceLineNo">6648</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6648"></a>
-<span class="sourceLineNo">6649</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6649"></a>
-<span class="sourceLineNo">6650</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6650"></a>
-<span class="sourceLineNo">6651</span>     * @param scannerContext<a name="line.6651"></a>
-<span class="sourceLineNo">6652</span>     * @param currentRowCell<a name="line.6652"></a>
-<span class="sourceLineNo">6653</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6653"></a>
-<span class="sourceLineNo">6654</span>     */<a name="line.6654"></a>
-<span class="sourceLineNo">6655</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6655"></a>
-<span class="sourceLineNo">6656</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6656"></a>
-<span class="sourceLineNo">6657</span>      Cell nextKv;<a name="line.6657"></a>
-<span class="sourceLineNo">6658</span>      boolean moreCellsInRow = false;<a name="line.6658"></a>
-<span class="sourceLineNo">6659</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6659"></a>
-<span class="sourceLineNo">6660</span>      // Scanning between column families and thus the scope is between cells<a name="line.6660"></a>
-<span class="sourceLineNo">6661</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6661"></a>
-<span class="sourceLineNo">6662</span>      do {<a name="line.6662"></a>
-<span class="sourceLineNo">6663</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6663"></a>
-<span class="sourceLineNo">6664</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6664"></a>
-<span class="sourceLineNo">6665</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6665"></a>
-<span class="sourceLineNo">6666</span>        scannerContext.setKeepProgress(true);<a name="line.6666"></a>
-<span class="sourceLineNo">6667</span>        heap.next(results, scannerContext);<a name="line.6667"></a>
-<span class="sourceLineNo">6668</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6668"></a>
-<span class="sourceLineNo">6669</span><a name="line.6669"></a>
-<span class="sourceLineNo">6670</span>        nextKv = heap.peek();<a name="line.6670"></a>
-<span class="sourceLineNo">6671</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6671"></a>
-<span class="sourceLineNo">6672</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6672"></a>
-<span class="sourceLineNo">6673</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6673"></a>
-<span class="sourceLineNo">6674</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6674"></a>
-<span class="sourceLineNo">6675</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6675"></a>
-<span class="sourceLineNo">6676</span>          ScannerContext.NextState state =<a name="line.6676"></a>
-<span class="sourceLineNo">6677</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6677"></a>
-<span class="sourceLineNo">6678</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6678"></a>
-<span class="sourceLineNo">6679</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6679"></a>
-<span class="sourceLineNo">6680</span>          ScannerContext.NextState state =<a name="line.6680"></a>
-<span class="sourceLineNo">6681</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6681"></a>
-<span class="sourceLineNo">6682</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6682"></a>
-<span class="sourceLineNo">6683</span>        }<a name="line.6683"></a>
-<span class="sourceLineNo">6684</span>      } while (moreCellsInRow);<a name="line.6684"></a>
-<span class="sourceLineNo">6685</span>      return nextKv != null;<a name="line.6685"></a>
-<span class="sourceLineNo">6686</span>    }<a name="line.6686"></a>
-<span class="sourceLineNo">6687</span><a name="line.6687"></a>
-<span class="sourceLineNo">6688</span>    /**<a name="line.6688"></a>
-<span class="sourceLineNo">6689</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6689"></a>
-<span class="sourceLineNo">6690</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6690"></a>
-<span class="sourceLineNo">6691</span>     * then there are more cells to be read in the row.<a name="line.6691"></a>
-<span class="sourceLineNo">6692</span>     * @param nextKv<a name="line.6692"></a>
-<span class="sourceLineNo">6693</span>     * @param currentRowCell<a name="line.6693"></a>
-<span class="sourceLineNo">6694</span>     * @return true When there are more cells in the row to be read<a name="line.6694"></a>
-<span class="sourceLineNo">6695</span>     */<a name="line.6695"></a>
-<span class="sourceLineNo">6696</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6696"></a>
-<span class="sourceLineNo">6697</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6697"></a>
-<span class="sourceLineNo">6698</span>    }<a name="line.6698"></a>
-<span class="sourceLineNo">6699</span><a name="line.6699"></a>
-<span class="sourceLineNo">6700</span>    /*<a name="line.6700"></a>
-<span class="sourceLineNo">6701</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6701"></a>
-<span class="sourceLineNo">6702</span>     */<a name="line.6702"></a>
-<span class="sourceLineNo">6703</span>    @Override<a name="line.6703"></a>
-<span class="sourceLineNo">6704</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6704"></a>
-<span class="sourceLineNo">6705</span>      return isFilterDoneInternal();<a name="line.6705"></a>
-<span class="sourceLineNo">6706</span>    }<a name="line.6706"></a>
-<span class="sourceLineNo">6707</span><a name="line.6707"></a>
-<span class="sourceLineNo">6708</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6708"></a>
-<span class="sourceLineNo">6709</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6709"></a>
-<span class="sourceLineNo">6710</span>    }<a name="line.6710"></a>
-<span class="sourceLineNo">6711</span><a name="line.6711"></a>
-<span class="sourceLineNo">6712</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6712"></a>
-<span class="sourceLineNo">6713</span>        throws IOException {<a name="line.6713"></a>
-<span class="sourceLineNo">6714</span>      if (!results.isEmpty()) {<a name="line.6714"></a>
-<span class="sourceLineNo">6715</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6715"></a>
-<span class="sourceLineNo">6716</span>      }<a name="line.6716"></a>
-<span class="sourceLineNo">6717</span>      if (scannerContext == null) {<a name="line.6717"></a>
-<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6718"></a>
+<span class="sourceLineNo">6340</span>            if (bulkLoadListener != null) {<a name="line.6340"></a>
+<span class="sourceLineNo">6341</span>              bulkLoadListener.doneBulkLoad(familyName, path);<a name="line.6341"></a>
+<span class="sourceLineNo">6342</span>            }<a name="line.6342"></a>
+<span class="sourceLineNo">6343</span>          } catch (IOException ioe) {<a name="line.6343"></a>
+<span class="sourceLineNo">6344</span>            // A failure here can cause an atomicity violation that we currently<a name="line.6344"></a>
+<span class="sourceLineNo">6345</span>            // cannot recover from since it is likely a failed HDFS operation.<a name="line.6345"></a>
+<span class="sourceLineNo">6346</span><a name="line.6346"></a>
+<span class="sourceLineNo">6347</span>            // TODO Need a better story for reverting partial failures due to HDFS.<a name="line.6347"></a>
+<span class="sourceLineNo">6348</span>            LOG.error("There was a partial failure due to IO when attempting to" +<a name="line.6348"></a>
+<span class="sourceLineNo">6349</span>                " load " + Bytes.toString(familyName) + " : " + p.getSecond(), ioe);<a name="line.6349"></a>
+<span class="sourceLineNo">6350</span>            if (bulkLoadListener != null) {<a name="line.6350"></a>
+<span class="sourceLineNo">6351</span>              try {<a name="line.6351"></a>
+<span class="sourceLineNo">6352</span>                bulkLoadListener.failedBulkLoad(familyName, path);<a name="line.6352"></a>
+<span class="sourceLineNo">6353</span>              } catch (Exception ex) {<a name="line.6353"></a>
+<span class="sourceLineNo">6354</span>                LOG.error("Error while calling failedBulkLoad for family " +<a name="line.6354"></a>
+<span class="sourceLineNo">6355</span>                    Bytes.toString(familyName) + " with path " + path, ex);<a name="line.6355"></a>
+<span class="sourceLineNo">6356</span>              }<a name="line.6356"></a>
+<span class="sourceLineNo">6357</span>            }<a name="line.6357"></a>
+<span class="sourceLineNo">6358</span>            throw ioe;<a name="line.6358"></a>
+<span class="sourceLineNo">6359</span>          }<a name="line.6359"></a>
+<span class="sourceLineNo">6360</span>        }<a name="line.6360"></a>
+<span class="sourceLineNo">6361</span>      }<a name="line.6361"></a>
+<span class="sourceLineNo">6362</span><a name="line.6362"></a>
+<span class="sourceLineNo">6363</span>      isSuccessful = true;<a name="line.6363"></a>
+<span class="sourceLineNo">6364</span>    } finally {<a name="line.6364"></a>
+<span class="sourceLineNo">6365</span>      if (wal != null &amp;&amp; !storeFiles.isEmpty()) {<a name="line.6365"></a>
+<span class="sourceLineNo">6366</span>        // Write a bulk load event for hfiles that are loaded<a name="line.6366"></a>
+<span class="sourceLineNo">6367</span>        try {<a name="line.6367"></a>
+<span class="sourceLineNo">6368</span>          WALProtos.BulkLoadDescriptor loadDescriptor =<a name="line.6368"></a>
+<span class="sourceLineNo">6369</span>              ProtobufUtil.toBulkLoadDescriptor(this.getRegionInfo().getTable(),<a name="line.6369"></a>
+<span class="sourceLineNo">6370</span>                  UnsafeByteOperations.unsafeWrap(this.getRegionInfo().getEncodedNameAsBytes()),<a name="line.6370"></a>
+<span class="sourceLineNo">6371</span>                  storeFiles,<a name="line.6371"></a>
+<span class="sourceLineNo">6372</span>                storeFilesSizes, seqId);<a name="line.6372"></a>
+<span class="sourceLineNo">6373</span>          WALUtil.writeBulkLoadMarkerAndSync(this.wal, this.getReplicationScope(), getRegionInfo(),<a name="line.6373"></a>
+<span class="sourceLineNo">6374</span>              loadDescriptor, mvcc);<a name="line.6374"></a>
+<span class="sourceLineNo">6375</span>        } catch (IOException ioe) {<a name="line.6375"></a>
+<span class="sourceLineNo">6376</span>          if (this.rsServices != null) {<a name="line.6376"></a>
+<span class="sourceLineNo">6377</span>            // Have to abort region server because some hfiles has been loaded but we can't write<a name="line.6377"></a>
+<span class="sourceLineNo">6378</span>            // the event into WAL<a name="line.6378"></a>
+<span class="sourceLineNo">6379</span>            isSuccessful = false;<a name="line.6379"></a>
+<span class="sourceLineNo">6380</span>            this.rsServices.abort("Failed to write bulk load event into WAL.", ioe);<a name="line.6380"></a>
+<span class="sourceLineNo">6381</span>          }<a name="line.6381"></a>
+<span class="sourceLineNo">6382</span>        }<a name="line.6382"></a>
+<span class="sourceLineNo">6383</span>      }<a name="line.6383"></a>
+<span class="sourceLineNo">6384</span><a name="line.6384"></a>
+<span class="sourceLineNo">6385</span>      closeBulkRegionOperation();<a name="line.6385"></a>
+<span class="sourceLineNo">6386</span>    }<a name="line.6386"></a>
+<span class="sourceLineNo">6387</span>    return isSuccessful ? storeFiles : null;<a name="line.6387"></a>
+<span class="sourceLineNo">6388</span>  }<a name="line.6388"></a>
+<span class="sourceLineNo">6389</span><a name="line.6389"></a>
+<span class="sourceLineNo">6390</span>  @Override<a name="line.6390"></a>
+<span class="sourceLineNo">6391</span>  public boolean equals(Object o) {<a name="line.6391"></a>
+<span class="sourceLineNo">6392</span>    return o instanceof HRegion &amp;&amp; Bytes.equals(getRegionInfo().getRegionName(),<a name="line.6392"></a>
+<span class="sourceLineNo">6393</span>                                                ((HRegion) o).getRegionInfo().getRegionName());<a name="line.6393"></a>
+<span class="sourceLineNo">6394</span>  }<a name="line.6394"></a>
+<span class="sourceLineNo">6395</span><a name="line.6395"></a>
+<span class="sourceLineNo">6396</span>  @Override<a name="line.6396"></a>
+<span class="sourceLineNo">6397</span>  public int hashCode() {<a name="line.6397"></a>
+<span class="sourceLineNo">6398</span>    return Bytes.hashCode(getRegionInfo().getRegionName());<a name="line.6398"></a>
+<span class="sourceLineNo">6399</span>  }<a name="line.6399"></a>
+<span class="sourceLineNo">6400</span><a name="line.6400"></a>
+<span class="sourceLineNo">6401</span>  @Override<a name="line.6401"></a>
+<span class="sourceLineNo">6402</span>  public String toString() {<a name="line.6402"></a>
+<span class="sourceLineNo">6403</span>    return getRegionInfo().getRegionNameAsString();<a name="line.6403"></a>
+<span class="sourceLineNo">6404</span>  }<a name="line.6404"></a>
+<span class="sourceLineNo">6405</span><a name="line.6405"></a>
+<span class="sourceLineNo">6406</span>  /**<a name="line.6406"></a>
+<span class="sourceLineNo">6407</span>   * RegionScannerImpl is used to combine scanners from multiple Stores (aka column families).<a name="line.6407"></a>
+<span class="sourceLineNo">6408</span>   */<a name="line.6408"></a>
+<span class="sourceLineNo">6409</span>  class RegionScannerImpl<a name="line.6409"></a>
+<span class="sourceLineNo">6410</span>      implements RegionScanner, Shipper, org.apache.hadoop.hbase.ipc.RpcCallback {<a name="line.6410"></a>
+<span class="sourceLineNo">6411</span>    // Package local for testability<a name="line.6411"></a>
+<span class="sourceLineNo">6412</span>    KeyValueHeap storeHeap = null;<a name="line.6412"></a>
+<span class="sourceLineNo">6413</span>    /** Heap of key-values that are not essential for the provided filters and are thus read<a name="line.6413"></a>
+<span class="sourceLineNo">6414</span>     * on demand, if on-demand column family loading is enabled.*/<a name="line.6414"></a>
+<span class="sourceLineNo">6415</span>    KeyValueHeap joinedHeap = null;<a name="line.6415"></a>
+<span class="sourceLineNo">6416</span>    /**<a name="line.6416"></a>
+<span class="sourceLineNo">6417</span>     * If the joined heap data gathering is interrupted due to scan limits, this will<a name="line.6417"></a>
+<span class="sourceLineNo">6418</span>     * contain the row for which we are populating the values.*/<a name="line.6418"></a>
+<span class="sourceLineNo">6419</span>    protected Cell joinedContinuationRow = null;<a name="line.6419"></a>
+<span class="sourceLineNo">6420</span>    private boolean filterClosed = false;<a name="line.6420"></a>
+<span class="sourceLineNo">6421</span><a name="line.6421"></a>
+<span class="sourceLineNo">6422</span>    protected final byte[] stopRow;<a name="line.6422"></a>
+<span class="sourceLineNo">6423</span>    protected final boolean includeStopRow;<a name="line.6423"></a>
+<span class="sourceLineNo">6424</span>    protected final HRegion region;<a name="line.6424"></a>
+<span class="sourceLineNo">6425</span>    protected final CellComparator comparator;<a name="line.6425"></a>
+<span class="sourceLineNo">6426</span><a name="line.6426"></a>
+<span class="sourceLineNo">6427</span>    private final long readPt;<a name="line.6427"></a>
+<span class="sourceLineNo">6428</span>    private final long maxResultSize;<a name="line.6428"></a>
+<span class="sourceLineNo">6429</span>    private final ScannerContext defaultScannerContext;<a name="line.6429"></a>
+<span class="sourceLineNo">6430</span>    private final FilterWrapper filter;<a name="line.6430"></a>
+<span class="sourceLineNo">6431</span><a name="line.6431"></a>
+<span class="sourceLineNo">6432</span>    @Override<a name="line.6432"></a>
+<span class="sourceLineNo">6433</span>    public RegionInfo getRegionInfo() {<a name="line.6433"></a>
+<span class="sourceLineNo">6434</span>      return region.getRegionInfo();<a name="line.6434"></a>
+<span class="sourceLineNo">6435</span>    }<a name="line.6435"></a>
+<span class="sourceLineNo">6436</span><a name="line.6436"></a>
+<span class="sourceLineNo">6437</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region)<a name="line.6437"></a>
+<span class="sourceLineNo">6438</span>        throws IOException {<a name="line.6438"></a>
+<span class="sourceLineNo">6439</span>      this(scan, additionalScanners, region, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.6439"></a>
+<span class="sourceLineNo">6440</span>    }<a name="line.6440"></a>
+<span class="sourceLineNo">6441</span><a name="line.6441"></a>
+<span class="sourceLineNo">6442</span>    RegionScannerImpl(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners, HRegion region,<a name="line.6442"></a>
+<span class="sourceLineNo">6443</span>        long nonceGroup, long nonce) throws IOException {<a name="line.6443"></a>
+<span class="sourceLineNo">6444</span>      this.region = region;<a name="line.6444"></a>
+<span class="sourceLineNo">6445</span>      this.maxResultSize = scan.getMaxResultSize();<a name="line.6445"></a>
+<span class="sourceLineNo">6446</span>      if (scan.hasFilter()) {<a name="line.6446"></a>
+<span class="sourceLineNo">6447</span>        this.filter = new FilterWrapper(scan.getFilter());<a name="line.6447"></a>
+<span class="sourceLineNo">6448</span>      } else {<a name="line.6448"></a>
+<span class="sourceLineNo">6449</span>        this.filter = null;<a name="line.6449"></a>
+<span class="sourceLineNo">6450</span>      }<a name="line.6450"></a>
+<span class="sourceLineNo">6451</span>      this.comparator = region.getCellComparator();<a name="line.6451"></a>
+<span class="sourceLineNo">6452</span>      /**<a name="line.6452"></a>
+<span class="sourceLineNo">6453</span>       * By default, calls to next/nextRaw must enforce the batch limit. Thus, construct a default<a name="line.6453"></a>
+<span class="sourceLineNo">6454</span>       * scanner context that can be used to enforce the batch limit in the event that a<a name="line.6454"></a>
+<span class="sourceLineNo">6455</span>       * ScannerContext is not specified during an invocation of next/nextRaw<a name="line.6455"></a>
+<span class="sourceLineNo">6456</span>       */<a name="line.6456"></a>
+<span class="sourceLineNo">6457</span>      defaultScannerContext = ScannerContext.newBuilder()<a name="line.6457"></a>
+<span class="sourceLineNo">6458</span>          .setBatchLimit(scan.getBatch()).build();<a name="line.6458"></a>
+<span class="sourceLineNo">6459</span>      this.stopRow = scan.getStopRow();<a name="line.6459"></a>
+<span class="sourceLineNo">6460</span>      this.includeStopRow = scan.includeStopRow();<a name="line.6460"></a>
+<span class="sourceLineNo">6461</span><a name="line.6461"></a>
+<span class="sourceLineNo">6462</span>      // synchronize on scannerReadPoints so that nobody calculates<a name="line.6462"></a>
+<span class="sourceLineNo">6463</span>      // getSmallestReadPoint, before scannerReadPoints is updated.<a name="line.6463"></a>
+<span class="sourceLineNo">6464</span>      IsolationLevel isolationLevel = scan.getIsolationLevel();<a name="line.6464"></a>
+<span class="sourceLineNo">6465</span>      long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);<a name="line.6465"></a>
+<span class="sourceLineNo">6466</span>      synchronized (scannerReadPoints) {<a name="line.6466"></a>
+<span class="sourceLineNo">6467</span>        if (mvccReadPoint &gt; 0) {<a name="line.6467"></a>
+<span class="sourceLineNo">6468</span>          this.readPt = mvccReadPoint;<a name="line.6468"></a>
+<span class="sourceLineNo">6469</span>        } else if (nonce == HConstants.NO_NONCE || rsServices == null<a name="line.6469"></a>
+<span class="sourceLineNo">6470</span>            || rsServices.getNonceManager() == null) {<a name="line.6470"></a>
+<span class="sourceLineNo">6471</span>          this.readPt = getReadPoint(isolationLevel);<a name="line.6471"></a>
+<span class="sourceLineNo">6472</span>        } else {<a name="line.6472"></a>
+<span class="sourceLineNo">6473</span>          this.readPt = rsServices.getNonceManager().getMvccFromOperationContext(nonceGroup, nonce);<a name="line.6473"></a>
+<span class="sourceLineNo">6474</span>        }<a name="line.6474"></a>
+<span class="sourceLineNo">6475</span>        scannerReadPoints.put(this, this.readPt);<a name="line.6475"></a>
+<span class="sourceLineNo">6476</span>      }<a name="line.6476"></a>
+<span class="sourceLineNo">6477</span>      initializeScanners(scan, additionalScanners);<a name="line.6477"></a>
+<span class="sourceLineNo">6478</span>    }<a name="line.6478"></a>
+<span class="sourceLineNo">6479</span><a name="line.6479"></a>
+<span class="sourceLineNo">6480</span>    protected void initializeScanners(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)<a name="line.6480"></a>
+<span class="sourceLineNo">6481</span>        throws IOException {<a name="line.6481"></a>
+<span class="sourceLineNo">6482</span>      // Here we separate all scanners into two lists - scanner that provide data required<a name="line.6482"></a>
+<span class="sourceLineNo">6483</span>      // by the filter to operate (scanners list) and all others (joinedScanners list).<a name="line.6483"></a>
+<span class="sourceLineNo">6484</span>      List&lt;KeyValueScanner&gt; scanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6484"></a>
+<span class="sourceLineNo">6485</span>      List&lt;KeyValueScanner&gt; joinedScanners = new ArrayList&lt;&gt;(scan.getFamilyMap().size());<a name="line.6485"></a>
+<span class="sourceLineNo">6486</span>      // Store all already instantiated scanners for exception handling<a name="line.6486"></a>
+<span class="sourceLineNo">6487</span>      List&lt;KeyValueScanner&gt; instantiatedScanners = new ArrayList&lt;&gt;();<a name="line.6487"></a>
+<span class="sourceLineNo">6488</span>      // handle additionalScanners<a name="line.6488"></a>
+<span class="sourceLineNo">6489</span>      if (additionalScanners != null &amp;&amp; !additionalScanners.isEmpty()) {<a name="line.6489"></a>
+<span class="sourceLineNo">6490</span>        scanners.addAll(additionalScanners);<a name="line.6490"></a>
+<span class="sourceLineNo">6491</span>        instantiatedScanners.addAll(additionalScanners);<a name="line.6491"></a>
+<span class="sourceLineNo">6492</span>      }<a name="line.6492"></a>
+<span class="sourceLineNo">6493</span><a name="line.6493"></a>
+<span class="sourceLineNo">6494</span>      try {<a name="line.6494"></a>
+<span class="sourceLineNo">6495</span>        for (Map.Entry&lt;byte[], NavigableSet&lt;byte[]&gt;&gt; entry : scan.getFamilyMap().entrySet()) {<a name="line.6495"></a>
+<span class="sourceLineNo">6496</span>          HStore store = stores.get(entry.getKey());<a name="line.6496"></a>
+<span class="sourceLineNo">6497</span>          KeyValueScanner scanner = store.getScanner(scan, entry.getValue(), this.readPt);<a name="line.6497"></a>
+<span class="sourceLineNo">6498</span>          instantiatedScanners.add(scanner);<a name="line.6498"></a>
+<span class="sourceLineNo">6499</span>          if (this.filter == null || !scan.doLoadColumnFamiliesOnDemand()<a name="line.6499"></a>
+<span class="sourceLineNo">6500</span>              || this.filter.isFamilyEssential(entry.getKey())) {<a name="line.6500"></a>
+<span class="sourceLineNo">6501</span>            scanners.add(scanner);<a name="line.6501"></a>
+<span class="sourceLineNo">6502</span>          } else {<a name="line.6502"></a>
+<span class="sourceLineNo">6503</span>            joinedScanners.add(scanner);<a name="line.6503"></a>
+<span class="sourceLineNo">6504</span>          }<a name="line.6504"></a>
+<span class="sourceLineNo">6505</span>        }<a name="line.6505"></a>
+<span class="sourceLineNo">6506</span>        initializeKVHeap(scanners, joinedScanners, region);<a name="line.6506"></a>
+<span class="sourceLineNo">6507</span>      } catch (Throwable t) {<a name="line.6507"></a>
+<span class="sourceLineNo">6508</span>        throw handleException(instantiatedScanners, t);<a name="line.6508"></a>
+<span class="sourceLineNo">6509</span>      }<a name="line.6509"></a>
+<span class="sourceLineNo">6510</span>    }<a name="line.6510"></a>
+<span class="sourceLineNo">6511</span><a name="line.6511"></a>
+<span class="sourceLineNo">6512</span>    protected void initializeKVHeap(List&lt;KeyValueScanner&gt; scanners,<a name="line.6512"></a>
+<span class="sourceLineNo">6513</span>        List&lt;KeyValueScanner&gt; joinedScanners, HRegion region)<a name="line.6513"></a>
+<span class="sourceLineNo">6514</span>        throws IOException {<a name="line.6514"></a>
+<span class="sourceLineNo">6515</span>      this.storeHeap = new KeyValueHeap(scanners, comparator);<a name="line.6515"></a>
+<span class="sourceLineNo">6516</span>      if (!joinedScanners.isEmpty()) {<a name="line.6516"></a>
+<span class="sourceLineNo">6517</span>        this.joinedHeap = new KeyValueHeap(joinedScanners, comparator);<a name="line.6517"></a>
+<span class="sourceLineNo">6518</span>      }<a name="line.6518"></a>
+<span class="sourceLineNo">6519</span>    }<a name="line.6519"></a>
+<span class="sourceLineNo">6520</span><a name="line.6520"></a>
+<span class="sourceLineNo">6521</span>    private IOException handleException(List&lt;KeyValueScanner&gt; instantiatedScanners,<a name="line.6521"></a>
+<span class="sourceLineNo">6522</span>        Throwable t) {<a name="line.6522"></a>
+<span class="sourceLineNo">6523</span>      // remove scaner read point before throw the exception<a name="line.6523"></a>
+<span class="sourceLineNo">6524</span>      scannerReadPoints.remove(this);<a name="line.6524"></a>
+<span class="sourceLineNo">6525</span>      if (storeHeap != null) {<a name="line.6525"></a>
+<span class="sourceLineNo">6526</span>        storeHeap.close();<a name="line.6526"></a>
+<span class="sourceLineNo">6527</span>        storeHeap = null;<a name="line.6527"></a>
+<span class="sourceLineNo">6528</span>        if (joinedHeap != null) {<a name="line.6528"></a>
+<span class="sourceLineNo">6529</span>          joinedHeap.close();<a name="line.6529"></a>
+<span class="sourceLineNo">6530</span>          joinedHeap = null;<a name="line.6530"></a>
+<span class="sourceLineNo">6531</span>        }<a name="line.6531"></a>
+<span class="sourceLineNo">6532</span>      } else {<a name="line.6532"></a>
+<span class="sourceLineNo">6533</span>        // close all already instantiated scanners before throwing the exception<a name="line.6533"></a>
+<span class="sourceLineNo">6534</span>        for (KeyValueScanner scanner : instantiatedScanners) {<a name="line.6534"></a>
+<span class="sourceLineNo">6535</span>          scanner.close();<a name="line.6535"></a>
+<span class="sourceLineNo">6536</span>        }<a name="line.6536"></a>
+<span class="sourceLineNo">6537</span>      }<a name="line.6537"></a>
+<span class="sourceLineNo">6538</span>      return t instanceof IOException ? (IOException) t : new IOException(t);<a name="line.6538"></a>
+<span class="sourceLineNo">6539</span>    }<a name="line.6539"></a>
+<span class="sourceLineNo">6540</span><a name="line.6540"></a>
+<span class="sourceLineNo">6541</span>    @Override<a name="line.6541"></a>
+<span class="sourceLineNo">6542</span>    public long getMaxResultSize() {<a name="line.6542"></a>
+<span class="sourceLineNo">6543</span>      return maxResultSize;<a name="line.6543"></a>
+<span class="sourceLineNo">6544</span>    }<a name="line.6544"></a>
+<span class="sourceLineNo">6545</span><a name="line.6545"></a>
+<span class="sourceLineNo">6546</span>    @Override<a name="line.6546"></a>
+<span class="sourceLineNo">6547</span>    public long getMvccReadPoint() {<a name="line.6547"></a>
+<span class="sourceLineNo">6548</span>      return this.readPt;<a name="line.6548"></a>
+<span class="sourceLineNo">6549</span>    }<a name="line.6549"></a>
+<span class="sourceLineNo">6550</span><a name="line.6550"></a>
+<span class="sourceLineNo">6551</span>    @Override<a name="line.6551"></a>
+<span class="sourceLineNo">6552</span>    public int getBatch() {<a name="line.6552"></a>
+<span class="sourceLineNo">6553</span>      return this.defaultScannerContext.getBatchLimit();<a name="line.6553"></a>
+<span class="sourceLineNo">6554</span>    }<a name="line.6554"></a>
+<span class="sourceLineNo">6555</span><a name="line.6555"></a>
+<span class="sourceLineNo">6556</span>    /**<a name="line.6556"></a>
+<span class="sourceLineNo">6557</span>     * Reset both the filter and the old filter.<a name="line.6557"></a>
+<span class="sourceLineNo">6558</span>     *<a name="line.6558"></a>
+<span class="sourceLineNo">6559</span>     * @throws IOException in case a filter raises an I/O exception.<a name="line.6559"></a>
+<span class="sourceLineNo">6560</span>     */<a name="line.6560"></a>
+<span class="sourceLineNo">6561</span>    protected void resetFilters() throws IOException {<a name="line.6561"></a>
+<span class="sourceLineNo">6562</span>      if (filter != null) {<a name="line.6562"></a>
+<span class="sourceLineNo">6563</span>        filter.reset();<a name="line.6563"></a>
+<span class="sourceLineNo">6564</span>      }<a name="line.6564"></a>
+<span class="sourceLineNo">6565</span>    }<a name="line.6565"></a>
+<span class="sourceLineNo">6566</span><a name="line.6566"></a>
+<span class="sourceLineNo">6567</span>    @Override<a name="line.6567"></a>
+<span class="sourceLineNo">6568</span>    public boolean next(List&lt;Cell&gt; outResults)<a name="line.6568"></a>
+<span class="sourceLineNo">6569</span>        throws IOException {<a name="line.6569"></a>
+<span class="sourceLineNo">6570</span>      // apply the batching limit by default<a name="line.6570"></a>
+<span class="sourceLineNo">6571</span>      return next(outResults, defaultScannerContext);<a name="line.6571"></a>
+<span class="sourceLineNo">6572</span>    }<a name="line.6572"></a>
+<span class="sourceLineNo">6573</span><a name="line.6573"></a>
+<span class="sourceLineNo">6574</span>    @Override<a name="line.6574"></a>
+<span class="sourceLineNo">6575</span>    public synchronized boolean next(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6575"></a>
+<span class="sourceLineNo">6576</span>    throws IOException {<a name="line.6576"></a>
+<span class="sourceLineNo">6577</span>      if (this.filterClosed) {<a name="line.6577"></a>
+<span class="sourceLineNo">6578</span>        throw new UnknownScannerException("Scanner was closed (timed out?) " +<a name="line.6578"></a>
+<span class="sourceLineNo">6579</span>            "after we renewed it. Could be caused by a very slow scanner " +<a name="line.6579"></a>
+<span class="sourceLineNo">6580</span>            "or a lengthy garbage collection");<a name="line.6580"></a>
+<span class="sourceLineNo">6581</span>      }<a name="line.6581"></a>
+<span class="sourceLineNo">6582</span>      startRegionOperation(Operation.SCAN);<a name="line.6582"></a>
+<span class="sourceLineNo">6583</span>      try {<a name="line.6583"></a>
+<span class="sourceLineNo">6584</span>        return nextRaw(outResults, scannerContext);<a name="line.6584"></a>
+<span class="sourceLineNo">6585</span>      } finally {<a name="line.6585"></a>
+<span class="sourceLineNo">6586</span>        closeRegionOperation(Operation.SCAN);<a name="line.6586"></a>
+<span class="sourceLineNo">6587</span>      }<a name="line.6587"></a>
+<span class="sourceLineNo">6588</span>    }<a name="line.6588"></a>
+<span class="sourceLineNo">6589</span><a name="line.6589"></a>
+<span class="sourceLineNo">6590</span>    @Override<a name="line.6590"></a>
+<span class="sourceLineNo">6591</span>    public boolean nextRaw(List&lt;Cell&gt; outResults) throws IOException {<a name="line.6591"></a>
+<span class="sourceLineNo">6592</span>      // Use the RegionScanner's context by default<a name="line.6592"></a>
+<span class="sourceLineNo">6593</span>      return nextRaw(outResults, defaultScannerContext);<a name="line.6593"></a>
+<span class="sourceLineNo">6594</span>    }<a name="line.6594"></a>
+<span class="sourceLineNo">6595</span><a name="line.6595"></a>
+<span class="sourceLineNo">6596</span>    @Override<a name="line.6596"></a>
+<span class="sourceLineNo">6597</span>    public boolean nextRaw(List&lt;Cell&gt; outResults, ScannerContext scannerContext)<a name="line.6597"></a>
+<span class="sourceLineNo">6598</span>        throws IOException {<a name="line.6598"></a>
+<span class="sourceLineNo">6599</span>      if (storeHeap == null) {<a name="line.6599"></a>
+<span class="sourceLineNo">6600</span>        // scanner is closed<a name="line.6600"></a>
+<span class="sourceLineNo">6601</span>        throw new UnknownScannerException("Scanner was closed");<a name="line.6601"></a>
+<span class="sourceLineNo">6602</span>      }<a name="line.6602"></a>
+<span class="sourceLineNo">6603</span>      boolean moreValues = false;<a name="line.6603"></a>
+<span class="sourceLineNo">6604</span>      if (outResults.isEmpty()) {<a name="line.6604"></a>
+<span class="sourceLineNo">6605</span>        // Usually outResults is empty. This is true when next is called<a name="line.6605"></a>
+<span class="sourceLineNo">6606</span>        // to handle scan or get operation.<a name="line.6606"></a>
+<span class="sourceLineNo">6607</span>        moreValues = nextInternal(outResults, scannerContext);<a name="line.6607"></a>
+<span class="sourceLineNo">6608</span>      } else {<a name="line.6608"></a>
+<span class="sourceLineNo">6609</span>        List&lt;Cell&gt; tmpList = new ArrayList&lt;&gt;();<a name="line.6609"></a>
+<span class="sourceLineNo">6610</span>        moreValues = nextInternal(tmpList, scannerContext);<a name="line.6610"></a>
+<span class="sourceLineNo">6611</span>        outResults.addAll(tmpList);<a name="line.6611"></a>
+<span class="sourceLineNo">6612</span>      }<a name="line.6612"></a>
+<span class="sourceLineNo">6613</span><a name="line.6613"></a>
+<span class="sourceLineNo">6614</span>      if (!outResults.isEmpty()) {<a name="line.6614"></a>
+<span class="sourceLineNo">6615</span>        readRequestsCount.increment();<a name="line.6615"></a>
+<span class="sourceLineNo">6616</span>      }<a name="line.6616"></a>
+<span class="sourceLineNo">6617</span><a name="line.6617"></a>
+<span class="sourceLineNo">6618</span>      // If the size limit was reached it means a partial Result is being returned. Returning a<a name="line.6618"></a>
+<span class="sourceLineNo">6619</span>      // partial Result means that we should not reset the filters; filters should only be reset in<a name="line.6619"></a>
+<span class="sourceLineNo">6620</span>      // between rows<a name="line.6620"></a>
+<span class="sourceLineNo">6621</span>      if (!scannerContext.mayHaveMoreCellsInRow()) {<a name="line.6621"></a>
+<span class="sourceLineNo">6622</span>        resetFilters();<a name="line.6622"></a>
+<span class="sourceLineNo">6623</span>      }<a name="line.6623"></a>
+<span class="sourceLineNo">6624</span><a name="line.6624"></a>
+<span class="sourceLineNo">6625</span>      if (isFilterDoneInternal()) {<a name="line.6625"></a>
+<span class="sourceLineNo">6626</span>        moreValues = false;<a name="line.6626"></a>
+<span class="sourceLineNo">6627</span>      }<a name="line.6627"></a>
+<span class="sourceLineNo">6628</span>      return moreValues;<a name="line.6628"></a>
+<span class="sourceLineNo">6629</span>    }<a name="line.6629"></a>
+<span class="sourceLineNo">6630</span><a name="line.6630"></a>
+<span class="sourceLineNo">6631</span>    /**<a name="line.6631"></a>
+<span class="sourceLineNo">6632</span>     * @return true if more cells exist after this batch, false if scanner is done<a name="line.6632"></a>
+<span class="sourceLineNo">6633</span>     */<a name="line.6633"></a>
+<span class="sourceLineNo">6634</span>    private boolean populateFromJoinedHeap(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6634"></a>
+<span class="sourceLineNo">6635</span>            throws IOException {<a name="line.6635"></a>
+<span class="sourceLineNo">6636</span>      assert joinedContinuationRow != null;<a name="line.6636"></a>
+<span class="sourceLineNo">6637</span>      boolean moreValues = populateResult(results, this.joinedHeap, scannerContext,<a name="line.6637"></a>
+<span class="sourceLineNo">6638</span>          joinedContinuationRow);<a name="line.6638"></a>
+<span class="sourceLineNo">6639</span><a name="line.6639"></a>
+<span class="sourceLineNo">6640</span>      if (!scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6640"></a>
+<span class="sourceLineNo">6641</span>        // We are done with this row, reset the continuation.<a name="line.6641"></a>
+<span class="sourceLineNo">6642</span>        joinedContinuationRow = null;<a name="line.6642"></a>
+<span class="sourceLineNo">6643</span>      }<a name="line.6643"></a>
+<span class="sourceLineNo">6644</span>      // As the data is obtained from two independent heaps, we need to<a name="line.6644"></a>
+<span class="sourceLineNo">6645</span>      // ensure that result list is sorted, because Result relies on that.<a name="line.6645"></a>
+<span class="sourceLineNo">6646</span>      sort(results, comparator);<a name="line.6646"></a>
+<span class="sourceLineNo">6647</span>      return moreValues;<a name="line.6647"></a>
+<span class="sourceLineNo">6648</span>    }<a name="line.6648"></a>
+<span class="sourceLineNo">6649</span><a name="line.6649"></a>
+<span class="sourceLineNo">6650</span>    /**<a name="line.6650"></a>
+<span class="sourceLineNo">6651</span>     * Fetches records with currentRow into results list, until next row, batchLimit (if not -1) is<a name="line.6651"></a>
+<span class="sourceLineNo">6652</span>     * reached, or remainingResultSize (if not -1) is reaced<a name="line.6652"></a>
+<span class="sourceLineNo">6653</span>     * @param heap KeyValueHeap to fetch data from.It must be positioned on correct row before call.<a name="line.6653"></a>
+<span class="sourceLineNo">6654</span>     * @param scannerContext<a name="line.6654"></a>
+<span class="sourceLineNo">6655</span>     * @param currentRowCell<a name="line.6655"></a>
+<span class="sourceLineNo">6656</span>     * @return state of last call to {@link KeyValueHeap#next()}<a name="line.6656"></a>
+<span class="sourceLineNo">6657</span>     */<a name="line.6657"></a>
+<span class="sourceLineNo">6658</span>    private boolean populateResult(List&lt;Cell&gt; results, KeyValueHeap heap,<a name="line.6658"></a>
+<span class="sourceLineNo">6659</span>        ScannerContext scannerContext, Cell currentRowCell) throws IOException {<a name="line.6659"></a>
+<span class="sourceLineNo">6660</span>      Cell nextKv;<a name="line.6660"></a>
+<span class="sourceLineNo">6661</span>      boolean moreCellsInRow = false;<a name="line.6661"></a>
+<span class="sourceLineNo">6662</span>      boolean tmpKeepProgress = scannerContext.getKeepProgress();<a name="line.6662"></a>
+<span class="sourceLineNo">6663</span>      // Scanning between column families and thus the scope is between cells<a name="line.6663"></a>
+<span class="sourceLineNo">6664</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6664"></a>
+<span class="sourceLineNo">6665</span>      do {<a name="line.6665"></a>
+<span class="sourceLineNo">6666</span>        // We want to maintain any progress that is made towards the limits while scanning across<a name="line.6666"></a>
+<span class="sourceLineNo">6667</span>        // different column families. To do this, we toggle the keep progress flag on during calls<a name="line.6667"></a>
+<span class="sourceLineNo">6668</span>        // to the StoreScanner to ensure that any progress made thus far is not wiped away.<a name="line.6668"></a>
+<span class="sourceLineNo">6669</span>        scannerContext.setKeepProgress(true);<a name="line.6669"></a>
+<span class="sourceLineNo">6670</span>        heap.next(results, scannerContext);<a name="line.6670"></a>
+<span class="sourceLineNo">6671</span>        scannerContext.setKeepProgress(tmpKeepProgress);<a name="line.6671"></a>
+<span class="sourceLineNo">6672</span><a name="line.6672"></a>
+<span class="sourceLineNo">6673</span>        nextKv = heap.peek();<a name="line.6673"></a>
+<span class="sourceLineNo">6674</span>        moreCellsInRow = moreCellsInRow(nextKv, currentRowCell);<a name="line.6674"></a>
+<span class="sourceLineNo">6675</span>        if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6675"></a>
+<span class="sourceLineNo">6676</span>        if (moreCellsInRow &amp;&amp; scannerContext.checkBatchLimit(limitScope)) {<a name="line.6676"></a>
+<span class="sourceLineNo">6677</span>          return scannerContext.setScannerState(NextState.BATCH_LIMIT_REACHED).hasMoreValues();<a name="line.6677"></a>
+<span class="sourceLineNo">6678</span>        } else if (scannerContext.checkSizeLimit(limitScope)) {<a name="line.6678"></a>
+<span class="sourceLineNo">6679</span>          ScannerContext.NextState state =<a name="line.6679"></a>
+<span class="sourceLineNo">6680</span>              moreCellsInRow ? NextState.SIZE_LIMIT_REACHED_MID_ROW : NextState.SIZE_LIMIT_REACHED;<a name="line.6680"></a>
+<span class="sourceLineNo">6681</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6681"></a>
+<span class="sourceLineNo">6682</span>        } else if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6682"></a>
+<span class="sourceLineNo">6683</span>          ScannerContext.NextState state =<a name="line.6683"></a>
+<span class="sourceLineNo">6684</span>              moreCellsInRow ? NextState.TIME_LIMIT_REACHED_MID_ROW : NextState.TIME_LIMIT_REACHED;<a name="line.6684"></a>
+<span class="sourceLineNo">6685</span>          return scannerContext.setScannerState(state).hasMoreValues();<a name="line.6685"></a>
+<span class="sourceLineNo">6686</span>        }<a name="line.6686"></a>
+<span class="sourceLineNo">6687</span>      } while (moreCellsInRow);<a name="line.6687"></a>
+<span class="sourceLineNo">6688</span>      return nextKv != null;<a name="line.6688"></a>
+<span class="sourceLineNo">6689</span>    }<a name="line.6689"></a>
+<span class="sourceLineNo">6690</span><a name="line.6690"></a>
+<span class="sourceLineNo">6691</span>    /**<a name="line.6691"></a>
+<span class="sourceLineNo">6692</span>     * Based on the nextKv in the heap, and the current row, decide whether or not there are more<a name="line.6692"></a>
+<span class="sourceLineNo">6693</span>     * cells to be read in the heap. If the row of the nextKv in the heap matches the current row<a name="line.6693"></a>
+<span class="sourceLineNo">6694</span>     * then there are more cells to be read in the row.<a name="line.6694"></a>
+<span class="sourceLineNo">6695</span>     * @param nextKv<a name="line.6695"></a>
+<span class="sourceLineNo">6696</span>     * @param currentRowCell<a name="line.6696"></a>
+<span class="sourceLineNo">6697</span>     * @return true When there are more cells in the row to be read<a name="line.6697"></a>
+<span class="sourceLineNo">6698</span>     */<a name="line.6698"></a>
+<span class="sourceLineNo">6699</span>    private boolean moreCellsInRow(final Cell nextKv, Cell currentRowCell) {<a name="line.6699"></a>
+<span class="sourceLineNo">6700</span>      return nextKv != null &amp;&amp; CellUtil.matchingRows(nextKv, currentRowCell);<a name="line.6700"></a>
+<span class="sourceLineNo">6701</span>    }<a name="line.6701"></a>
+<span class="sourceLineNo">6702</span><a name="line.6702"></a>
+<span class="sourceLineNo">6703</span>    /*<a name="line.6703"></a>
+<span class="sourceLineNo">6704</span>     * @return True if a filter rules the scanner is over, done.<a name="line.6704"></a>
+<span class="sourceLineNo">6705</span>     */<a name="line.6705"></a>
+<span class="sourceLineNo">6706</span>    @Override<a name="line.6706"></a>
+<span class="sourceLineNo">6707</span>    public synchronized boolean isFilterDone() throws IOException {<a name="line.6707"></a>
+<span class="sourceLineNo">6708</span>      return isFilterDoneInternal();<a name="line.6708"></a>
+<span class="sourceLineNo">6709</span>    }<a name="line.6709"></a>
+<span class="sourceLineNo">6710</span><a name="line.6710"></a>
+<span class="sourceLineNo">6711</span>    private boolean isFilterDoneInternal() throws IOException {<a name="line.6711"></a>
+<span class="sourceLineNo">6712</span>      return this.filter != null &amp;&amp; this.filter.filterAllRemaining();<a name="line.6712"></a>
+<span class="sourceLineNo">6713</span>    }<a name="line.6713"></a>
+<span class="sourceLineNo">6714</span><a name="line.6714"></a>
+<span class="sourceLineNo">6715</span>    private boolean nextInternal(List&lt;Cell&gt; results, ScannerContext scannerContext)<a name="line.6715"></a>
+<span class="sourceLineNo">6716</span>        throws IOException {<a name="line.6716"></a>
+<span class="sourceLineNo">6717</span>      if (!results.isEmpty()) {<a name="line.6717"></a>
+<span class="sourceLineNo">6718</span>        throw new IllegalArgumentException("First parameter should be an empty list");<a name="line.6718"></a>
 <span class="sourceLineNo">6719</span>      }<a name="line.6719"></a>
-<span class="sourceLineNo">6720</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6720"></a>
-<span class="sourceLineNo">6721</span><a name="line.6721"></a>
-<span class="sourceLineNo">6722</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6722"></a>
-<span class="sourceLineNo">6723</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6723"></a>
-<span class="sourceLineNo">6724</span>      // progress.<a name="line.6724"></a>
-<span class="sourceLineNo">6725</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6725"></a>
-<span class="sourceLineNo">6726</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6726"></a>
-<span class="sourceLineNo">6727</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6727"></a>
-<span class="sourceLineNo">6728</span><a name="line.6728"></a>
-<span class="sourceLineNo">6729</span>      // Used to check time limit<a name="line.6729"></a>
-<span class="sourceLineNo">6730</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6730"></a>
+<span class="sourceLineNo">6720</span>      if (scannerContext == null) {<a name="line.6720"></a>
+<span class="sourceLineNo">6721</span>        throw new IllegalArgumentException("Scanner context cannot be null");<a name="line.6721"></a>
+<span class="sourceLineNo">6722</span>      }<a name="line.6722"></a>
+<span class="sourceLineNo">6723</span>      Optional&lt;RpcCall&gt; rpcCall = RpcServer.getCurrentCall();<a name="line.6723"></a>
+<span class="sourceLineNo">6724</span><a name="line.6724"></a>
+<span class="sourceLineNo">6725</span>      // Save the initial progress from the Scanner context in these local variables. The progress<a name="line.6725"></a>
+<span class="sourceLineNo">6726</span>      // may need to be reset a few times if rows are being filtered out so we save the initial<a name="line.6726"></a>
+<span class="sourceLineNo">6727</span>      // progress.<a name="line.6727"></a>
+<span class="sourceLineNo">6728</span>      int initialBatchProgress = scannerContext.getBatchProgress();<a name="line.6728"></a>
+<span class="sourceLineNo">6729</span>      long initialSizeProgress = scannerContext.getDataSizeProgress();<a name="line.6729"></a>
+<span class="sourceLineNo">6730</span>      long initialHeapSizeProgress = scannerContext.getHeapSizeProgress();<a name="line.6730"></a>
 <span class="sourceLineNo">6731</span><a name="line.6731"></a>
-<span class="sourceLineNo">6732</span>      // The loop here is used only when at some point during the next we determine<a name="line.6732"></a>
-<span class="sourceLineNo">6733</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6733"></a>
-<span class="sourceLineNo">6734</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6734"></a>
-<span class="sourceLineNo">6735</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6735"></a>
-<span class="sourceLineNo">6736</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6736"></a>
-<span class="sourceLineNo">6737</span>      while (true) {<a name="line.6737"></a>
-<span class="sourceLineNo">6738</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6738"></a>
-<span class="sourceLineNo">6739</span>        // progress should be kept.<a name="line.6739"></a>
-<span class="sourceLineNo">6740</span>        if (scannerContext.getKeepProgress()) {<a name="line.6740"></a>
-<span class="sourceLineNo">6741</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6741"></a>
-<span class="sourceLineNo">6742</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6742"></a>
-<span class="sourceLineNo">6743</span>              initialHeapSizeProgress);<a name="line.6743"></a>
-<span class="sourceLineNo">6744</span>        } else {<a name="line.6744"></a>
-<span class="sourceLineNo">6745</span>          scannerContext.clearProgress();<a name="line.6745"></a>
-<span class="sourceLineNo">6746</span>        }<a name="line.6746"></a>
-<span class="sourceLineNo">6747</span>        if (rpcCall.isPresent()) {<a name="line.6747"></a>
-<span class="sourceLineNo">6748</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6748"></a>
-<span class="sourceLineNo">6749</span>          // client might time out and disconnect while the server side<a name="line.6749"></a>
-<span class="sourceLineNo">6750</span>          // is still processing the request. We should abort aggressively<a name="line.6750"></a>
-<span class="sourceLineNo">6751</span>          // in that case.<a name="line.6751"></a>
-<span class="sourceLineNo">6752</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6752"></a>
-<span class="sourceLineNo">6753</span>          if (afterTime &gt;= 0) {<a name="line.6753"></a>
-<span class="sourceLineNo">6754</span>            throw new CallerDisconnectedException(<a name="line.6754"></a>
-<span class="sourceLineNo">6755</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6755"></a>
-<span class="sourceLineNo">6756</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6756"></a>
-<span class="sourceLineNo">6757</span>                    "caller disconnected");<a name="line.6757"></a>
-<span class="sourceLineNo">6758</span>          }<a name="line.6758"></a>
-<span class="sourceLineNo">6759</span>        }<a name="line.6759"></a>
-<span class="sourceLineNo">6760</span><a name="line.6760"></a>
-<span class="sourceLineNo">6761</span>        // Let's see what we have in the storeHeap.<a name="line.6761"></a>
-<span class="sourceLineNo">6762</span>        Cell current = this.storeHeap.peek();<a name="line.6762"></a>
+<span class="sourceLineNo">6732</span>      // Used to check time limit<a name="line.6732"></a>
+<span class="sourceLineNo">6733</span>      LimitScope limitScope = LimitScope.BETWEEN_CELLS;<a name="line.6733"></a>
+<span class="sourceLineNo">6734</span><a name="line.6734"></a>
+<span class="sourceLineNo">6735</span>      // The loop here is used only when at some point during the next we determine<a name="line.6735"></a>
+<span class="sourceLineNo">6736</span>      // that due to effects of filters or otherwise, we have an empty row in the result.<a name="line.6736"></a>
+<span class="sourceLineNo">6737</span>      // Then we loop and try again. Otherwise, we must get out on the first iteration via return,<a name="line.6737"></a>
+<span class="sourceLineNo">6738</span>      // "true" if there's more data to read, "false" if there isn't (storeHeap is at a stop row,<a name="line.6738"></a>
+<span class="sourceLineNo">6739</span>      // and joinedHeap has no more data to read for the last row (if set, joinedContinuationRow).<a name="line.6739"></a>
+<span class="sourceLineNo">6740</span>      while (true) {<a name="line.6740"></a>
+<span class="sourceLineNo">6741</span>        // Starting to scan a new row. Reset the scanner progress according to whether or not<a name="line.6741"></a>
+<span class="sourceLineNo">6742</span>        // progress should be kept.<a name="line.6742"></a>
+<span class="sourceLineNo">6743</span>        if (scannerContext.getKeepProgress()) {<a name="line.6743"></a>
+<span class="sourceLineNo">6744</span>          // Progress should be kept. Reset to initial values seen at start of method invocation.<a name="line.6744"></a>
+<span class="sourceLineNo">6745</span>          scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6745"></a>
+<span class="sourceLineNo">6746</span>              initialHeapSizeProgress);<a name="line.6746"></a>
+<span class="sourceLineNo">6747</span>        } else {<a name="line.6747"></a>
+<span class="sourceLineNo">6748</span>          scannerContext.clearProgress();<a name="line.6748"></a>
+<span class="sourceLineNo">6749</span>        }<a name="line.6749"></a>
+<span class="sourceLineNo">6750</span>        if (rpcCall.isPresent()) {<a name="line.6750"></a>
+<span class="sourceLineNo">6751</span>          // If a user specifies a too-restrictive or too-slow scanner, the<a name="line.6751"></a>
+<span class="sourceLineNo">6752</span>          // client might time out and disconnect while the server side<a name="line.6752"></a>
+<span class="sourceLineNo">6753</span>          // is still processing the request. We should abort aggressively<a name="line.6753"></a>
+<span class="sourceLineNo">6754</span>          // in that case.<a name="line.6754"></a>
+<span class="sourceLineNo">6755</span>          long afterTime = rpcCall.get().disconnectSince();<a name="line.6755"></a>
+<span class="sourceLineNo">6756</span>          if (afterTime &gt;= 0) {<a name="line.6756"></a>
+<span class="sourceLineNo">6757</span>            throw new CallerDisconnectedException(<a name="line.6757"></a>
+<span class="sourceLineNo">6758</span>                "Aborting on region " + getRegionInfo().getRegionNameAsString() + ", call " +<a name="line.6758"></a>
+<span class="sourceLineNo">6759</span>                    this + " after " + afterTime + " ms, since " +<a name="line.6759"></a>
+<span class="sourceLineNo">6760</span>                    "caller disconnected");<a name="line.6760"></a>
+<span class="sourceLineNo">6761</span>          }<a name="line.6761"></a>
+<span class="sourceLineNo">6762</span>        }<a name="line.6762"></a>
 <span class="sourceLineNo">6763</span><a name="line.6763"></a>
-<span class="sourceLineNo">6764</span>        boolean shouldStop = shouldStop(current);<a name="line.6764"></a>
-<span class="sourceLineNo">6765</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6765"></a>
-<span class="sourceLineNo">6766</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6766"></a>
-<span class="sourceLineNo">6767</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6767"></a>
-<span class="sourceLineNo">6768</span>        // table that has very large rows.<a name="line.6768"></a>
-<span class="sourceLineNo">6769</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6769"></a>
-<span class="sourceLineNo">6770</span><a name="line.6770"></a>
-<span class="sourceLineNo">6771</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6771"></a>
-<span class="sourceLineNo">6772</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6772"></a>
-<span class="sourceLineNo">6773</span>        // scope of any limits that could potentially create partial results to<a name="line.6773"></a>
-<span class="sourceLineNo">6774</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6774"></a>
-<span class="sourceLineNo">6775</span>        if (hasFilterRow) {<a name="line.6775"></a>
-<span class="sourceLineNo">6776</span>          if (LOG.isTraceEnabled()) {<a name="line.6776"></a>
-<span class="sourceLineNo">6777</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6777"></a>
-<span class="sourceLineNo">6778</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6778"></a>
-<span class="sourceLineNo">6779</span>          }<a name="line.6779"></a>
-<span class="sourceLineNo">6780</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6780"></a>
-<span class="sourceLineNo">6781</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6781"></a>
-<span class="sourceLineNo">6782</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6782"></a>
-<span class="sourceLineNo">6783</span>        }<a name="line.6783"></a>
-<span class="sourceLineNo">6784</span><a name="line.6784"></a>
-<span class="sourceLineNo">6785</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6785"></a>
-<span class="sourceLineNo">6786</span>          if (hasFilterRow) {<a name="line.6786"></a>
-<span class="sourceLineNo">6787</span>            throw new IncompatibleFilterException(<a name="line.6787"></a>
-<span class="sourceLineNo">6788</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6788"></a>
-<span class="sourceLineNo">6789</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6789"></a>
-<span class="sourceLineNo">6790</span>          }<a name="line.6790"></a>
-<span class="sourceLineNo">6791</span>          return true;<a name="line.6791"></a>
-<span class="sourceLineNo">6792</span>        }<a name="line.6792"></a>
-<span class="sourceLineNo">6793</span><a name="line.6793"></a>
-<span class="sourceLineNo">6794</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6794"></a>
-<span class="sourceLineNo">6795</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6795"></a>
-<span class="sourceLineNo">6796</span>        if (joinedContinuationRow == null) {<a name="line.6796"></a>
-<span class="sourceLineNo">6797</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6797"></a>
-<span class="sourceLineNo">6798</span>          if (shouldStop) {<a name="line.6798"></a>
-<span class="sourceLineNo">6799</span>            if (hasFilterRow) {<a name="line.6799"></a>
-<span class="sourceLineNo">6800</span>              filter.filterRowCells(results);<a name="line.6800"></a>
-<span class="sourceLineNo">6801</span>            }<a name="line.6801"></a>
-<span class="sourceLineNo">6802</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6802"></a>
-<span class="sourceLineNo">6803</span>          }<a name="line.6803"></a>
-<span class="sourceLineNo">6804</span><a name="line.6804"></a>
-<span class="sourceLineNo">6805</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6805"></a>
-<span class="sourceLineNo">6806</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6806"></a>
-<span class="sourceLineNo">6807</span>          if (filterRowKey(current)) {<a name="line.6807"></a>
-<span class="sourceLineNo">6808</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6808"></a>
-<span class="sourceLineNo">6809</span>            // early check, see HBASE-16296<a name="line.6809"></a>
-<span class="sourceLineNo">6810</span>            if (isFilterDoneInternal()) {<a name="line.6810"></a>
-<span class="sourceLineNo">6811</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6811"></a>
-<span class="sourceLineNo">6812</span>            }<a name="line.6812"></a>
-<span class="sourceLineNo">6813</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6813"></a>
-<span class="sourceLineNo">6814</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6814"></a>
-<span class="sourceLineNo">6815</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6815"></a>
-<span class="sourceLineNo">6816</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6816"></a>
-<span class="sourceLineNo">6817</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6817"></a>
-<span class="sourceLineNo">6818</span>            if (!moreRows) {<a name="line.6818"></a>
-<span class="sourceLineNo">6819</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6819"></a>
-<span class="sourceLineNo">6820</span>            }<a name="line.6820"></a>
-<span class="sourceLineNo">6821</span>            results.clear();<a name="line.6821"></a>
-<span class="sourceLineNo">6822</span><a name="line.6822"></a>
-<span class="sourceLineNo">6823</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6823"></a>
-<span class="sourceLineNo">6824</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6824"></a>
-<span class="sourceLineNo">6825</span>              return true;<a name="line.6825"></a>
-<span class="sourceLineNo">6826</span>            }<a name="line.6826"></a>
-<span class="sourceLineNo">6827</span>            continue;<a name="line.6827"></a>
-<span class="sourceLineNo">6828</span>          }<a name="line.6828"></a>
-<span class="sourceLineNo">6829</span><a name="line.6829"></a>
-<span class="sourceLineNo">6830</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6830"></a>
-<span class="sourceLineNo">6831</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6831"></a>
-<span class="sourceLineNo">6832</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6832"></a>
-<span class="sourceLineNo">6833</span>            if (hasFilterRow) {<a name="line.6833"></a>
-<span class="sourceLineNo">6834</span>              throw new IncompatibleFilterException(<a name="line.6834"></a>
-<span class="sourceLineNo">6835</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6835"></a>
-<span class="sourceLineNo">6836</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6836"></a>
-<span class="sourceLineNo">6837</span>            }<a name="line.6837"></a>
-<span class="sourceLineNo">6838</span>            return true;<a name="line.6838"></a>
-<span class="sourceLineNo">6839</span>          }<a name="line.6839"></a>
-<span class="sourceLineNo">6840</span><a name="line.6840"></a>
-<span class="sourceLineNo">6841</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6841"></a>
-<span class="sourceLineNo">6842</span>          shouldStop = shouldStop(nextKv);<a name="line.6842"></a>
-<span class="sourceLineNo">6843</span>          // save that the row was empty before filters applied to it.<a name="line.6843"></a>
-<span class="sourceLineNo">6844</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6844"></a>
-<span class="sourceLineNo">6845</span><a name="line.6845"></a>
-<span class="sourceLineNo">6846</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6846"></a>
-<span class="sourceLineNo">6847</span>          // First filter with the filterRow(List).<a name="line.6847"></a>
-<span class="sourceLineNo">6848</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6848"></a>
-<span class="sourceLineNo">6849</span>          if (hasFilterRow) {<a name="line.6849"></a>
-<span class="sourceLineNo">6850</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6850"></a>
-<span class="sourceLineNo">6851</span><a name="line.6851"></a>
-<span class="sourceLineNo">6852</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6852"></a>
-<span class="sourceLineNo">6853</span>            // according to contents of results now.<a name="line.6853"></a>
-<span class="sourceLineNo">6854</span>            if (scannerContext.getKeepProgress()) {<a name="line.6854"></a>
-<span class="sourceLineNo">6855</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6855"></a>
-<span class="sourceLineNo">6856</span>                  initialHeapSizeProgress);<a name="line.6856"></a>
-<span class="sourceLineNo">6857</span>            } else {<a name="line.6857"></a>
-<span class="sourceLineNo">6858</span>              scannerContext.clearProgress();<a name="line.6858"></a>
-<span class="sourceLineNo">6859</span>            }<a name="line.6859"></a>
-<span class="sourceLineNo">6860</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6860"></a>
-<span class="sourceLineNo">6861</span>            for (Cell cell : results) {<a name="line.6861"></a>
-<span class="sourceLineNo">6862</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6862"></a>
-<span class="sourceLineNo">6863</span>                cell.heapSize());<a name="line.6863"></a>
-<span class="sourceLineNo">6864</span>            }<a name="line.6864"></a>
-<span class="sourceLineNo">6865</span>          }<a name="line.6865"></a>
-<span class="sourceLineNo">6866</span><a name="line.6866"></a>
-<span class="sourceLineNo">6867</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6867"></a>
-<span class="sourceLineNo">6868</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6868"></a>
-<span class="sourceLineNo">6869</span>            results.clear();<a name="line.6869"></a>
-<span class="sourceLineNo">6870</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6870"></a>
-<span class="sourceLineNo">6871</span>            if (!moreRows) {<a name="line.6871"></a>
-<span class="sourceLineNo">6872</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6872"></a>
-<span class="sourceLineNo">6873</span>            }<a name="line.6873"></a>
-<span class="sourceLineNo">6874</span><a name="line.6874"></a>
-<span class="sourceLineNo">6875</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6875"></a>
-<span class="sourceLineNo">6876</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6876"></a>
-<span class="sourceLineNo">6877</span>            if (!shouldStop) {<a name="line.6877"></a>
-<span class="sourceLineNo">6878</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6878"></a>
-<span class="sourceLineNo">6879</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6879"></a>
-<span class="sourceLineNo">6880</span>                return true;<a name="line.6880"></a>
-<span class="sourceLineNo">6881</span>              }<a name="line.6881"></a>
-<span class="sourceLineNo">6882</span>              continue;<a name="line.6882"></a>
-<span class="sourceLineNo">6883</span>            }<a name="line.6883"></a>
-<span class="sourceLineNo">6884</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6884"></a>
-<span class="sourceLineNo">6885</span>          }<a name="line.6885"></a>
-<span class="sourceLineNo">6886</span><a name="line.6886"></a>
-<span class="sourceLineNo">6887</span>          // Ok, we are done with storeHeap for this row.<a name="line.6887"></a>
-<span class="sourceLineNo">6888</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6888"></a>
-<span class="sourceLineNo">6889</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6889"></a>
-<span class="sourceLineNo">6890</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6890"></a>
-<span class="sourceLineNo">6891</span>          if (this.joinedHeap != null) {<a name="line.6891"></a>
-<span class="sourceLineNo">6892</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6892"></a>
-<span class="sourceLineNo">6893</span>            if (mayHaveData) {<a name="line.6893"></a>
-<span class="sourceLineNo">6894</span>              joinedContinuationRow = current;<a name="line.6894"></a>
-<span class="sourceLineNo">6895</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6895"></a>
-<span class="sourceLineNo">6896</span><a name="line.6896"></a>
-<span class="sourceLineNo">6897</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6897"></a>
-<span class="sourceLineNo">6898</span>                return true;<a name="line.6898"></a>
-<span class="sourceLineNo">6899</span>              }<a name="line.6899"></a>
-<span class="sourceLineNo">6900</span>            }<a name="line.6900"></a>
-<span class="sourceLineNo">6901</span>          }<a name="line.6901"></a>
-<span class="sourceLineNo">6902</span>        } else {<a name="line.6902"></a>
-<span class="sourceLineNo">6903</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6903"></a>
-<span class="sourceLineNo">6904</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6904"></a>
-<span class="sourceLineNo">6905</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6905"></a>
-<span class="sourceLineNo">6906</span>            return true;<a name="line.6906"></a>
-<span class="sourceLineNo">6907</span>          }<a name="line.6907"></a>
-<span class="sourceLineNo">6908</span>        }<a name="line.6908"></a>
-<span class="sourceLineNo">6909</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6909"></a>
-<span class="sourceLineNo">6910</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6910"></a>
-<span class="sourceLineNo">6911</span>        if (joinedContinuationRow != null) {<a name="line.6911"></a>
-<span class="sourceLineNo">6912</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6912"></a>
-<span class="sourceLineNo">6913</span>        }<a name="line.6913"></a>
-<span class="sourceLineNo">6914</span><a name="line.6914"></a>
-<span class="sourceLineNo">6915</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6915"></a>
-<span class="sourceLineNo">6916</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6916"></a>
-<span class="sourceLineNo">6917</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6917"></a>
-<span class="sourceLineNo">6918</span>        if (results.isEmpty()) {<a name="line.6918"></a>
-<span class="sourceLineNo">6919</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6919"></a>
-<span class="sourceLineNo">6920</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6920"></a>
-<span class="sourceLineNo">6921</span>          if (!moreRows) {<a name="line.6921"></a>
-<span class="sourceLineNo">6922</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6922"></a>
-<span class="sourceLineNo">6923</span>          }<a name="line.6923"></a>
-<span class="sourceLineNo">6924</span>          if (!shouldStop) continue;<a name="line.6924"></a>
-<span class="sourceLineNo">6925</span>        }<a name="line.6925"></a>
-<span class="sourceLineNo">6926</span><a name="line.6926"></a>
-<span class="sourceLineNo">6927</span>        if (shouldStop) {<a name="line.6927"></a>
-<span class="sourceLineNo">6928</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6928"></a>
-<span class="sourceLineNo">6929</span>        } else {<a name="line.6929"></a>
-<span class="sourceLineNo">6930</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6930"></a>
-<span class="sourceLineNo">6931</span>        }<a name="line.6931"></a>
-<span class="sourceLineNo">6932</span>      }<a name="line.6932"></a>
-<span class="sourceLineNo">6933</span>    }<a name="line.6933"></a>
-<span class="sourceLineNo">6934</span><a name="line.6934"></a>
-<span class="sourceLineNo">6935</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6935"></a>
-<span class="sourceLineNo">6936</span>      filteredReadRequestsCount.increment();<a name="line.6936"></a>
+<span class="sourceLineNo">6764</span>        // Let's see what we have in the storeHeap.<a name="line.6764"></a>
+<span class="sourceLineNo">6765</span>        Cell current = this.storeHeap.peek();<a name="line.6765"></a>
+<span class="sourceLineNo">6766</span><a name="line.6766"></a>
+<span class="sourceLineNo">6767</span>        boolean shouldStop = shouldStop(current);<a name="line.6767"></a>
+<span class="sourceLineNo">6768</span>        // When has filter row is true it means that the all the cells for a particular row must be<a name="line.6768"></a>
+<span class="sourceLineNo">6769</span>        // read before a filtering decision can be made. This means that filters where hasFilterRow<a name="line.6769"></a>
+<span class="sourceLineNo">6770</span>        // run the risk of enLongAddering out of memory errors in the case that they are applied to a<a name="line.6770"></a>
+<span class="sourceLineNo">6771</span>        // table that has very large rows.<a name="line.6771"></a>
+<span class="sourceLineNo">6772</span>        boolean hasFilterRow = this.filter != null &amp;&amp; this.filter.hasFilterRow();<a name="line.6772"></a>
+<span class="sourceLineNo">6773</span><a name="line.6773"></a>
+<span class="sourceLineNo">6774</span>        // If filter#hasFilterRow is true, partial results are not allowed since allowing them<a name="line.6774"></a>
+<span class="sourceLineNo">6775</span>        // would prevent the filters from being evaluated. Thus, if it is true, change the<a name="line.6775"></a>
+<span class="sourceLineNo">6776</span>        // scope of any limits that could potentially create partial results to<a name="line.6776"></a>
+<span class="sourceLineNo">6777</span>        // LimitScope.BETWEEN_ROWS so that those limits are not reached mid-row<a name="line.6777"></a>
+<span class="sourceLineNo">6778</span>        if (hasFilterRow) {<a name="line.6778"></a>
+<span class="sourceLineNo">6779</span>          if (LOG.isTraceEnabled()) {<a name="line.6779"></a>
+<span class="sourceLineNo">6780</span>            LOG.trace("filter#hasFilterRow is true which prevents partial results from being "<a name="line.6780"></a>
+<span class="sourceLineNo">6781</span>                + " formed. Changing scope of limits that may create partials");<a name="line.6781"></a>
+<span class="sourceLineNo">6782</span>          }<a name="line.6782"></a>
+<span class="sourceLineNo">6783</span>          scannerContext.setSizeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6783"></a>
+<span class="sourceLineNo">6784</span>          scannerContext.setTimeLimitScope(LimitScope.BETWEEN_ROWS);<a name="line.6784"></a>
+<span class="sourceLineNo">6785</span>          limitScope = LimitScope.BETWEEN_ROWS;<a name="line.6785"></a>
+<span class="sourceLineNo">6786</span>        }<a name="line.6786"></a>
+<span class="sourceLineNo">6787</span><a name="line.6787"></a>
+<span class="sourceLineNo">6788</span>        if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {<a name="line.6788"></a>
+<span class="sourceLineNo">6789</span>          if (hasFilterRow) {<a name="line.6789"></a>
+<span class="sourceLineNo">6790</span>            throw new IncompatibleFilterException(<a name="line.6790"></a>
+<span class="sourceLineNo">6791</span>                "Filter whose hasFilterRow() returns true is incompatible with scans that must " +<a name="line.6791"></a>
+<span class="sourceLineNo">6792</span>                    " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6792"></a>
+<span class="sourceLineNo">6793</span>          }<a name="line.6793"></a>
+<span class="sourceLineNo">6794</span>          return true;<a name="line.6794"></a>
+<span class="sourceLineNo">6795</span>        }<a name="line.6795"></a>
+<span class="sourceLineNo">6796</span><a name="line.6796"></a>
+<span class="sourceLineNo">6797</span>        // Check if we were getting data from the joinedHeap and hit the limit.<a name="line.6797"></a>
+<span class="sourceLineNo">6798</span>        // If not, then it's main path - getting results from storeHeap.<a name="line.6798"></a>
+<span class="sourceLineNo">6799</span>        if (joinedContinuationRow == null) {<a name="line.6799"></a>
+<span class="sourceLineNo">6800</span>          // First, check if we are at a stop row. If so, there are no more results.<a name="line.6800"></a>
+<span class="sourceLineNo">6801</span>          if (shouldStop) {<a name="line.6801"></a>
+<span class="sourceLineNo">6802</span>            if (hasFilterRow) {<a name="line.6802"></a>
+<span class="sourceLineNo">6803</span>              filter.filterRowCells(results);<a name="line.6803"></a>
+<span class="sourceLineNo">6804</span>            }<a name="line.6804"></a>
+<span class="sourceLineNo">6805</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6805"></a>
+<span class="sourceLineNo">6806</span>          }<a name="line.6806"></a>
+<span class="sourceLineNo">6807</span><a name="line.6807"></a>
+<span class="sourceLineNo">6808</span>          // Check if rowkey filter wants to exclude this row. If so, loop to next.<a name="line.6808"></a>
+<span class="sourceLineNo">6809</span>          // Technically, if we hit limits before on this row, we don't need this call.<a name="line.6809"></a>
+<span class="sourceLineNo">6810</span>          if (filterRowKey(current)) {<a name="line.6810"></a>
+<span class="sourceLineNo">6811</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6811"></a>
+<span class="sourceLineNo">6812</span>            // early check, see HBASE-16296<a name="line.6812"></a>
+<span class="sourceLineNo">6813</span>            if (isFilterDoneInternal()) {<a name="line.6813"></a>
+<span class="sourceLineNo">6814</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6814"></a>
+<span class="sourceLineNo">6815</span>            }<a name="line.6815"></a>
+<span class="sourceLineNo">6816</span>            // Typically the count of rows scanned is incremented inside #populateResult. However,<a name="line.6816"></a>
+<span class="sourceLineNo">6817</span>            // here we are filtering a row based purely on its row key, preventing us from calling<a name="line.6817"></a>
+<span class="sourceLineNo">6818</span>            // #populateResult. Thus, perform the necessary increment here to rows scanned metric<a name="line.6818"></a>
+<span class="sourceLineNo">6819</span>            incrementCountOfRowsScannedMetric(scannerContext);<a name="line.6819"></a>
+<span class="sourceLineNo">6820</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6820"></a>
+<span class="sourceLineNo">6821</span>            if (!moreRows) {<a name="line.6821"></a>
+<span class="sourceLineNo">6822</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6822"></a>
+<span class="sourceLineNo">6823</span>            }<a name="line.6823"></a>
+<span class="sourceLineNo">6824</span>            results.clear();<a name="line.6824"></a>
+<span class="sourceLineNo">6825</span><a name="line.6825"></a>
+<span class="sourceLineNo">6826</span>            // Read nothing as the rowkey was filtered, but still need to check time limit<a name="line.6826"></a>
+<span class="sourceLineNo">6827</span>            if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6827"></a>
+<span class="sourceLineNo">6828</span>              return true;<a name="line.6828"></a>
+<span class="sourceLineNo">6829</span>            }<a name="line.6829"></a>
+<span class="sourceLineNo">6830</span>            continue;<a name="line.6830"></a>
+<span class="sourceLineNo">6831</span>          }<a name="line.6831"></a>
+<span class="sourceLineNo">6832</span><a name="line.6832"></a>
+<span class="sourceLineNo">6833</span>          // Ok, we are good, let's try to get some results from the main heap.<a name="line.6833"></a>
+<span class="sourceLineNo">6834</span>          populateResult(results, this.storeHeap, scannerContext, current);<a name="line.6834"></a>
+<span class="sourceLineNo">6835</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6835"></a>
+<span class="sourceLineNo">6836</span>            if (hasFilterRow) {<a name="line.6836"></a>
+<span class="sourceLineNo">6837</span>              throw new IncompatibleFilterException(<a name="line.6837"></a>
+<span class="sourceLineNo">6838</span>                  "Filter whose hasFilterRow() returns true is incompatible with scans that must "<a name="line.6838"></a>
+<span class="sourceLineNo">6839</span>                      + " stop mid-row because of a limit. ScannerContext:" + scannerContext);<a name="line.6839"></a>
+<span class="sourceLineNo">6840</span>            }<a name="line.6840"></a>
+<span class="sourceLineNo">6841</span>            return true;<a name="line.6841"></a>
+<span class="sourceLineNo">6842</span>          }<a name="line.6842"></a>
+<span class="sourceLineNo">6843</span><a name="line.6843"></a>
+<span class="sourceLineNo">6844</span>          Cell nextKv = this.storeHeap.peek();<a name="line.6844"></a>
+<span class="sourceLineNo">6845</span>          shouldStop = shouldStop(nextKv);<a name="line.6845"></a>
+<span class="sourceLineNo">6846</span>          // save that the row was empty before filters applied to it.<a name="line.6846"></a>
+<span class="sourceLineNo">6847</span>          final boolean isEmptyRow = results.isEmpty();<a name="line.6847"></a>
+<span class="sourceLineNo">6848</span><a name="line.6848"></a>
+<span class="sourceLineNo">6849</span>          // We have the part of the row necessary for filtering (all of it, usually).<a name="line.6849"></a>
+<span class="sourceLineNo">6850</span>          // First filter with the filterRow(List).<a name="line.6850"></a>
+<span class="sourceLineNo">6851</span>          FilterWrapper.FilterRowRetCode ret = FilterWrapper.FilterRowRetCode.NOT_CALLED;<a name="line.6851"></a>
+<span class="sourceLineNo">6852</span>          if (hasFilterRow) {<a name="line.6852"></a>
+<span class="sourceLineNo">6853</span>            ret = filter.filterRowCellsWithRet(results);<a name="line.6853"></a>
+<span class="sourceLineNo">6854</span><a name="line.6854"></a>
+<span class="sourceLineNo">6855</span>            // We don't know how the results have changed after being filtered. Must set progress<a name="line.6855"></a>
+<span class="sourceLineNo">6856</span>            // according to contents of results now.<a name="line.6856"></a>
+<span class="sourceLineNo">6857</span>            if (scannerContext.getKeepProgress()) {<a name="line.6857"></a>
+<span class="sourceLineNo">6858</span>              scannerContext.setProgress(initialBatchProgress, initialSizeProgress,<a name="line.6858"></a>
+<span class="sourceLineNo">6859</span>                  initialHeapSizeProgress);<a name="line.6859"></a>
+<span class="sourceLineNo">6860</span>            } else {<a name="line.6860"></a>
+<span class="sourceLineNo">6861</span>              scannerContext.clearProgress();<a name="line.6861"></a>
+<span class="sourceLineNo">6862</span>            }<a name="line.6862"></a>
+<span class="sourceLineNo">6863</span>            scannerContext.incrementBatchProgress(results.size());<a name="line.6863"></a>
+<span class="sourceLineNo">6864</span>            for (Cell cell : results) {<a name="line.6864"></a>
+<span class="sourceLineNo">6865</span>              scannerContext.incrementSizeProgress(PrivateCellUtil.estimatedSerializedSizeOf(cell),<a name="line.6865"></a>
+<span class="sourceLineNo">6866</span>                cell.heapSize());<a name="line.6866"></a>
+<span class="sourceLineNo">6867</span>            }<a name="line.6867"></a>
+<span class="sourceLineNo">6868</span>          }<a name="line.6868"></a>
+<span class="sourceLineNo">6869</span><a name="line.6869"></a>
+<span class="sourceLineNo">6870</span>          if (isEmptyRow || ret == FilterWrapper.FilterRowRetCode.EXCLUDE || filterRow()) {<a name="line.6870"></a>
+<span class="sourceLineNo">6871</span>            incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6871"></a>
+<span class="sourceLineNo">6872</span>            results.clear();<a name="line.6872"></a>
+<span class="sourceLineNo">6873</span>            boolean moreRows = nextRow(scannerContext, current);<a name="line.6873"></a>
+<span class="sourceLineNo">6874</span>            if (!moreRows) {<a name="line.6874"></a>
+<span class="sourceLineNo">6875</span>              return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6875"></a>
+<span class="sourceLineNo">6876</span>            }<a name="line.6876"></a>
+<span class="sourceLineNo">6877</span><a name="line.6877"></a>
+<span class="sourceLineNo">6878</span>            // This row was totally filtered out, if this is NOT the last row,<a name="line.6878"></a>
+<span class="sourceLineNo">6879</span>            // we should continue on. Otherwise, nothing else to do.<a name="line.6879"></a>
+<span class="sourceLineNo">6880</span>            if (!shouldStop) {<a name="line.6880"></a>
+<span class="sourceLineNo">6881</span>              // Read nothing as the cells was filtered, but still need to check time limit<a name="line.6881"></a>
+<span class="sourceLineNo">6882</span>              if (scannerContext.checkTimeLimit(limitScope)) {<a name="line.6882"></a>
+<span class="sourceLineNo">6883</span>                return true;<a name="line.6883"></a>
+<span class="sourceLineNo">6884</span>              }<a name="line.6884"></a>
+<span class="sourceLineNo">6885</span>              continue;<a name="line.6885"></a>
+<span class="sourceLineNo">6886</span>            }<a name="line.6886"></a>
+<span class="sourceLineNo">6887</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6887"></a>
+<span class="sourceLineNo">6888</span>          }<a name="line.6888"></a>
+<span class="sourceLineNo">6889</span><a name="line.6889"></a>
+<span class="sourceLineNo">6890</span>          // Ok, we are done with storeHeap for this row.<a name="line.6890"></a>
+<span class="sourceLineNo">6891</span>          // Now we may need to fetch additional, non-essential data into row.<a name="line.6891"></a>
+<span class="sourceLineNo">6892</span>          // These values are not needed for filter to work, so we postpone their<a name="line.6892"></a>
+<span class="sourceLineNo">6893</span>          // fetch to (possibly) reduce amount of data loads from disk.<a name="line.6893"></a>
+<span class="sourceLineNo">6894</span>          if (this.joinedHeap != null) {<a name="line.6894"></a>
+<span class="sourceLineNo">6895</span>            boolean mayHaveData = joinedHeapMayHaveData(current);<a name="line.6895"></a>
+<span class="sourceLineNo">6896</span>            if (mayHaveData) {<a name="line.6896"></a>
+<span class="sourceLineNo">6897</span>              joinedContinuationRow = current;<a name="line.6897"></a>
+<span class="sourceLineNo">6898</span>              populateFromJoinedHeap(results, scannerContext);<a name="line.6898"></a>
+<span class="sourceLineNo">6899</span><a name="line.6899"></a>
+<span class="sourceLineNo">6900</span>              if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6900"></a>
+<span class="sourceLineNo">6901</span>                return true;<a name="line.6901"></a>
+<span class="sourceLineNo">6902</span>              }<a name="line.6902"></a>
+<span class="sourceLineNo">6903</span>            }<a name="line.6903"></a>
+<span class="sourceLineNo">6904</span>          }<a name="line.6904"></a>
+<span class="sourceLineNo">6905</span>        } else {<a name="line.6905"></a>
+<span class="sourceLineNo">6906</span>          // Populating from the joined heap was stopped by limits, populate some more.<a name="line.6906"></a>
+<span class="sourceLineNo">6907</span>          populateFromJoinedHeap(results, scannerContext);<a name="line.6907"></a>
+<span class="sourceLineNo">6908</span>          if (scannerContext.checkAnyLimitReached(LimitScope.BETWEEN_CELLS)) {<a name="line.6908"></a>
+<span class="sourceLineNo">6909</span>            return true;<a name="line.6909"></a>
+<span class="sourceLineNo">6910</span>          }<a name="line.6910"></a>
+<span class="sourceLineNo">6911</span>        }<a name="line.6911"></a>
+<span class="sourceLineNo">6912</span>        // We may have just called populateFromJoinedMap and hit the limits. If that is<a name="line.6912"></a>
+<span class="sourceLineNo">6913</span>        // the case, we need to call it again on the next next() invocation.<a name="line.6913"></a>
+<span class="sourceLineNo">6914</span>        if (joinedContinuationRow != null) {<a name="line.6914"></a>
+<span class="sourceLineNo">6915</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6915"></a>
+<span class="sourceLineNo">6916</span>        }<a name="line.6916"></a>
+<span class="sourceLineNo">6917</span><a name="line.6917"></a>
+<span class="sourceLineNo">6918</span>        // Finally, we are done with both joinedHeap and storeHeap.<a name="line.6918"></a>
+<span class="sourceLineNo">6919</span>        // Double check to prevent empty rows from appearing in result. It could be<a name="line.6919"></a>
+<span class="sourceLineNo">6920</span>        // the case when SingleColumnValueExcludeFilter is used.<a name="line.6920"></a>
+<span class="sourceLineNo">6921</span>        if (results.isEmpty()) {<a name="line.6921"></a>
+<span class="sourceLineNo">6922</span>          incrementCountOfRowsFilteredMetric(scannerContext);<a name="line.6922"></a>
+<span class="sourceLineNo">6923</span>          boolean moreRows = nextRow(scannerContext, current);<a name="line.6923"></a>
+<span class="sourceLineNo">6924</span>          if (!moreRows) {<a name="line.6924"></a>
+<span class="sourceLineNo">6925</span>            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6925"></a>
+<span class="sourceLineNo">6926</span>          }<a name="line.6926"></a>
+<span class="sourceLineNo">6927</span>          if (!shouldStop) continue;<a name="line.6927"></a>
+<span class="sourceLineNo">6928</span>        }<a name="line.6928"></a>
+<span class="sourceLineNo">6929</span><a name="line.6929"></a>
+<span class="sourceLineNo">6930</span>        if (shouldStop) {<a name="line.6930"></a>
+<span class="sourceLineNo">6931</span>          return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();<a name="line.6931"></a>
+<span class="sourceLineNo">6932</span>        } else {<a name="line.6932"></a>
+<span class="sourceLineNo">6933</span>          return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();<a name="line.6933"></a>
+<span class="sourceLineNo">6934</span>        }<a name="line.6934"></a>
+<span class="sourceLineNo">6935</span>      }<a name="line.6935"></a>
+<span class="sourceLineNo">6936</span>    }<a name="line.6936"></a>
 <span class="sourceLineNo">6937</span><a name="line.6937"></a>
-<span class="sourceLineNo">6938</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6938"></a>
-<span class="sourceLineNo">6939</span><a name="line.6939"></a>
-<span class="sourceLineNo">6940</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6940"></a>
-<span class="sourceLineNo">6941</span>    }<a name="line.6941"></a>
+<span class="sourceLineNo">6938</span>    protected void incrementCountOfRowsFilteredMetric(ScannerContext scannerContext) {<a name="line.6938"></a>
+<span class="sourceLineNo">6939</span>      filteredReadRequestsCount.increment();<a name="line.6939"></a>
+<span class="sourceLineNo">6940</span><a name="line.6940"></a>
+<span class="sourceLineNo">6941</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6941"></a>
 <span class="sourceLineNo">6942</span><a name="line.6942"></a>
-<span class="sourceLineNo">6943</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6943"></a>
-<span class="sourceLineNo">6944</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6944"></a>
+<span class="sourceLineNo">6943</span>      scannerContext.getMetrics().countOfRowsFiltered.incrementAndGet();<a name="line.6943"></a>
+<span class="sourceLineNo">6944</span>    }<a name="line.6944"></a>
 <span class="sourceLineNo">6945</span><a name="line.6945"></a>
-<span class="sourceLineNo">6946</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6946"></a>
-<span class="sourceLineNo">6947</span>    }<a name="line.6947"></a>
+<span class="sourceLineNo">6946</span>    protected void incrementCountOfRowsScannedMetric(ScannerContext scannerContext) {<a name="line.6946"></a>
+<span class="sourceLineNo">6947</span>      if (scannerContext == null || !scannerContext.isTrackingMetrics()) return;<a name="line.6947"></a>
 <span class="sourceLineNo">6948</span><a name="line.6948"></a>
-<span class="sourceLineNo">6949</span>    /**<a name="line.6949"></a>
-<span class="sourceLineNo">6950</span>     * @param currentRowCell<a name="line.6950"></a>
-<span class="sourceLineNo">6951</span>     * @return true when the joined heap may have data for the current row<a name="line.6951"></a>
-<span class="sourceLineNo">6952</span>     * @throws IOException<a name="line.6952"></a>
-<span class="sourceLineNo">6953</span>     */<a name="line.6953"></a>
-<span class="sourceLineNo">6954</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6954"></a>
-<span class="sourceLineNo">6955</span>        throws IOException {<a name="line.6955"></a>
-<span class="sourceLineNo">6956</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6956"></a>
-<span class="sourceLineNo">6957</span>      boolean matchCurrentRow =<a name="line.6957"></a>
-<span class="sourceLineNo">6958</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6958"></a>
-<span class="sourceLineNo">6959</span>      boolean matchAfterSeek = false;<a name="line.6959"></a>
-<span class="sourceLineNo">6960</span><a name="line.6960"></a>
-<span class="sourceLineNo">6961</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6961"></a>
-<span class="sourceLineNo">6962</span>      // correct row<a name="line.6962"></a>
-<span class="sourceLineNo">6963</span>      if (!matchCurrentRow) {<a name="line.6963"></a>
-<span class="sourceLineNo">6964</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6964"></a>
-<span class="sourceLineNo">6965</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6965"></a>
-<span class="sourceLineNo">6966</span>        matchAfterSeek =<a name="line.6966"></a>
-<span class="sourceLineNo">6967</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6967"></a>
-<span class="sourceLineNo">6968</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6968"></a>
-<span class="sourceLineNo">6969</span>      }<a name="line.6969"></a>
-<span class="sourceLineNo">6970</span><a name="line.6970"></a>
-<span class="sourceLineNo">6971</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6971"></a>
-<span class="sourceLineNo">6972</span>    }<a name="line.6972"></a>
+<span class="sourceLineNo">6949</span>      scannerContext.getMetrics().countOfRowsScanned.incrementAndGet();<a name="line.6949"></a>
+<span class="sourceLineNo">6950</span>    }<a name="line.6950"></a>
+<span class="sourceLineNo">6951</span><a name="line.6951"></a>
+<span class="sourceLineNo">6952</span>    /**<a name="line.6952"></a>
+<span class="sourceLineNo">6953</span>     * @param currentRowCell<a name="line.6953"></a>
+<span class="sourceLineNo">6954</span>     * @return true when the joined heap may have data for the current row<a name="line.6954"></a>
+<span class="sourceLineNo">6955</span>     * @throws IOException<a name="line.6955"></a>
+<span class="sourceLineNo">6956</span>     */<a name="line.6956"></a>
+<span class="sourceLineNo">6957</span>    private boolean joinedHeapMayHaveData(Cell currentRowCell)<a name="line.6957"></a>
+<span class="sourceLineNo">6958</span>        throws IOException {<a name="line.6958"></a>
+<span class="sourceLineNo">6959</span>      Cell nextJoinedKv = joinedHeap.peek();<a name="line.6959"></a>
+<span class="sourceLineNo">6960</span>      boolean matchCurrentRow =<a name="line.6960"></a>
+<span class="sourceLineNo">6961</span>          nextJoinedKv != null &amp;&amp; CellUtil.matchingRows(nextJoinedKv, currentRowCell);<a name="line.6961"></a>
+<span class="sourceLineNo">6962</span>      boolean matchAfterSeek = false;<a name="line.6962"></a>
+<span class="sourceLineNo">6963</span><a name="line.6963"></a>
+<span class="sourceLineNo">6964</span>      // If the next value in the joined heap does not match the current row, try to seek to the<a name="line.6964"></a>
+<span class="sourceLineNo">6965</span>      // correct row<a name="line.6965"></a>
+<span class="sourceLineNo">6966</span>      if (!matchCurrentRow) {<a name="line.6966"></a>
+<span class="sourceLineNo">6967</span>        Cell firstOnCurrentRow = PrivateCellUtil.createFirstOnRow(currentRowCell);<a name="line.6967"></a>
+<span class="sourceLineNo">6968</span>        boolean seekSuccessful = this.joinedHeap.requestSeek(firstOnCurrentRow, true, true);<a name="line.6968"></a>
+<span class="sourceLineNo">6969</span>        matchAfterSeek =<a name="line.6969"></a>
+<span class="sourceLineNo">6970</span>            seekSuccessful &amp;&amp; joinedHeap.peek() != null<a name="line.6970"></a>
+<span class="sourceLineNo">6971</span>                &amp;&amp; CellUtil.matchingRows(joinedHeap.peek(), currentRowCell);<a name="line.6971"></a>
+<span class="sourceLineNo">6972</span>      }<a name="line.6972"></a>
 <span class="sourceLineNo">6973</span><a name="line.6973"></a>
-<span class="sourceLineNo">6974</span>    /**<a name="line.6974"></a>
-<span class="sourceLineNo">6975</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6975"></a>
-<span class="sourceLineNo">6976</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6976"></a>
-<span class="sourceLineNo">6977</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6977"></a>
-<span class="sourceLineNo">6978</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6978"></a>
-<span class="sourceLineNo">6979</span>     * Therefore, the filterRow() will be skipped.<a name="line.6979"></a>
-<span class="sourceLineNo">6980</span>     */<a name="line.6980"></a>
-<span class="sourceLineNo">6981</span>    private boolean filterRow() throws IOException {<a name="line.6981"></a>
-<span class="sourceLineNo">6982</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6982"></a>
-<span class="sourceLineNo">6983</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6983"></a>
-<span class="sourceLineNo">6984</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6984"></a>
-<span class="sourceLineNo">6985</span>          &amp;&amp; filter.filterRow();<a name="line.6985"></a>
-<span class="sourceLineNo">6986</span>    }<a name="line.6986"></a>
-<span class="sourceLineNo">6987</span><a name="line.6987"></a>
-<span class="sourceLineNo">6988</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6988"></a>
-<span class="sourceLineNo">6989</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6989"></a>
-<span class="sourceLineNo">6990</span>    }<a name="line.6990"></a>
-<span class="sourceLineNo">6991</span><a name="line.6991"></a>
-<span class="sourceLineNo">6992</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6992"></a>
-<span class="sourceLineNo">6993</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6993"></a>
-<span class="sourceLineNo">6994</span>      Cell next;<a name="line.6994"></a>
-<span class="sourceLineNo">6995</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6995"></a>
-<span class="sourceLineNo">6996</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6996"></a>
-<span class="sourceLineNo">6997</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.6997"></a>
-<span class="sourceLineNo">6998</span>      }<a name="line.6998"></a>
-<span class="sourceLineNo">6999</span>      resetFilters();<a name="line.6999"></a>
-<span class="sourceLineNo">7000</span><a name="line.7000"></a>
-<span class="sourceLineNo">7001</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7001"></a>
-<span class="sourceLineNo">7002</span>      return this.region.getCoprocessorHost() == null<a name="line.7002"></a>
-<span class="sourceLineNo">7003</span>          || this.region.getCoprocessorHost()<a name="line.7003"></a>
-<span class="sourceLineNo">7004</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7004"></a>
-<span class="sourceLineNo">7005</span>    }<a name="line.7005"></a>
-<span class="sourceLineNo">7006</span><a name="line.7006"></a>
-<span class="sourceLineNo">7007</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7007"></a>
-<span class="sourceLineNo">7008</span>      if (currentRowCell == null) {<a name="line.7008"></a>
-<span class="sourceLineNo">7009</span>        return true;<a name="line.7009"></a>
-<span class="sourceLineNo">7010</span>      }<a name="line.7010"></a>
-<span class="sourceLineNo">7011</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7011"></a>
-<span class="sourceLineNo">7012</span>        return false;<a name="line.7012"></a>
+<span class="sourceLineNo">6974</span>      return matchCurrentRow || matchAfterSeek;<a name="line.6974"></a>
+<span class="sourceLineNo">6975</span>    }<a name="line.6975"></a>
+<span class="sourceLineNo">6976</span><a name="line.6976"></a>
+<span class="sourceLineNo">6977</span>    /**<a name="line.6977"></a>
+<span class="sourceLineNo">6978</span>     * This function is to maintain backward compatibility for 0.94 filters. HBASE-6429 combines<a name="line.6978"></a>
+<span class="sourceLineNo">6979</span>     * both filterRow &amp; filterRow({@code List&lt;KeyValue&gt; kvs}) functions. While 0.94 code or older,<a name="line.6979"></a>
+<span class="sourceLineNo">6980</span>     * it may not implement hasFilterRow as HBase-6429 expects because 0.94 hasFilterRow() only<a name="line.6980"></a>
+<span class="sourceLineNo">6981</span>     * returns true when filterRow({@code List&lt;KeyValue&gt; kvs}) is overridden not the filterRow().<a name="line.6981"></a>
+<span class="sourceLineNo">6982</span>     * Therefore, the filterRow() will be skipped.<a name="line.6982"></a>
+<span class="sourceLineNo">6983</span>     */<a name="line.6983"></a>
+<span class="sourceLineNo">6984</span>    private boolean filterRow() throws IOException {<a name="line.6984"></a>
+<span class="sourceLineNo">6985</span>      // when hasFilterRow returns true, filter.filterRow() will be called automatically inside<a name="line.6985"></a>
+<span class="sourceLineNo">6986</span>      // filterRowCells(List&lt;Cell&gt; kvs) so we skip that scenario here.<a name="line.6986"></a>
+<span class="sourceLineNo">6987</span>      return filter != null &amp;&amp; (!filter.hasFilterRow())<a name="line.6987"></a>
+<span class="sourceLineNo">6988</span>          &amp;&amp; filter.filterRow();<a name="line.6988"></a>
+<span class="sourceLineNo">6989</span>    }<a name="line.6989"></a>
+<span class="sourceLineNo">6990</span><a name="line.6990"></a>
+<span class="sourceLineNo">6991</span>    private boolean filterRowKey(Cell current) throws IOException {<a name="line.6991"></a>
+<span class="sourceLineNo">6992</span>      return filter != null &amp;&amp; filter.filterRowKey(current);<a name="line.6992"></a>
+<span class="sourceLineNo">6993</span>    }<a name="line.6993"></a>
+<span class="sourceLineNo">6994</span><a name="line.6994"></a>
+<span class="sourceLineNo">6995</span>    protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException {<a name="line.6995"></a>
+<span class="sourceLineNo">6996</span>      assert this.joinedContinuationRow == null: "Trying to go to next row during joinedHeap read.";<a name="line.6996"></a>
+<span class="sourceLineNo">6997</span>      Cell next;<a name="line.6997"></a>
+<span class="sourceLineNo">6998</span>      while ((next = this.storeHeap.peek()) != null &amp;&amp;<a name="line.6998"></a>
+<span class="sourceLineNo">6999</span>             CellUtil.matchingRows(next, curRowCell)) {<a name="line.6999"></a>
+<span class="sourceLineNo">7000</span>        this.storeHeap.next(MOCKED_LIST);<a name="line.7000"></a>
+<span class="sourceLineNo">7001</span>      }<a name="line.7001"></a>
+<span class="sourceLineNo">7002</span>      resetFilters();<a name="line.7002"></a>
+<span class="sourceLineNo">7003</span><a name="line.7003"></a>
+<span class="sourceLineNo">7004</span>      // Calling the hook in CP which allows it to do a fast forward<a name="line.7004"></a>
+<span class="sourceLineNo">7005</span>      return this.region.getCoprocessorHost() == null<a name="line.7005"></a>
+<span class="sourceLineNo">7006</span>          || this.region.getCoprocessorHost()<a name="line.7006"></a>
+<span class="sourceLineNo">7007</span>              .postScannerFilterRow(this, curRowCell);<a name="line.7007"></a>
+<span class="sourceLineNo">7008</span>    }<a name="line.7008"></a>
+<span class="sourceLineNo">7009</span><a name="line.7009"></a>
+<span class="sourceLineNo">7010</span>    protected boolean shouldStop(Cell currentRowCell) {<a name="line.7010"></a>
+<span class="sourceLineNo">7011</span>      if (currentRowCell == null) {<a name="line.7011"></a>
+<span class="sourceLineNo">7012</span>        return true;<a name="line.7012"></a>
 <span class="sourceLineNo">7013</span>      }<a name="line.7013"></a>
-<span class="sourceLineNo">7014</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7014"></a>
-<span class="sourceLineNo">7015</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7015"></a>
-<span class="sourceLineNo">7016</span>    }<a name="line.7016"></a>
-<span class="sourceLineNo">7017</span><a name="line.7017"></a>
-<span class="sourceLineNo">7018</span>    @Override<a name="line.7018"></a>
-<span class="sourceLineNo">7019</span>    public synchronized void close() {<a name="line.7019"></a>
-<span class="sourceLineNo">7020</span>      if (storeHeap != null) {<a name="line.7020"></a>
-<span class="sourceLineNo">7021</span>        storeHeap.close();<a name="line.7021"></a>
-<span class="sourceLineNo">7022</span>        storeHeap = null;<a name="line.7022"></a>
-<span class="sourceLineNo">7023</span>      }<a name="line.7023"></a>
-<span class="sourceLineNo">7024</span>      if (joinedHeap != null) {<a name="line.7024"></a>
-<span class="sourceLineNo">7025</span>        joinedHeap.close();<a name="line.7025"></a>
-<span class="sourceLineNo">7026</span>        joinedHeap = null;<a name="line.7026"></a>
-<span class="sourceLineNo">7027</span>      }<a name="line.7027"></a>
-<span class="sourceLineNo">7028</span>      // no need to synchronize here.<a name="line.7028"></a>
-<span class="sourceLineNo">7029</span>      scannerReadPoints.remove(this);<a name="line.7029"></a>
-<span class="sourceLineNo">7030</span>      this.filterClosed = true;<a name="line.7030"></a>
-<span class="sourceLineNo">7031</span>    }<a name="line.7031"></a>
-<span class="sourceLineNo">7032</span><a name="line.7032"></a>
-<span class="sourceLineNo">7033</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7033"></a>
-<span class="sourceLineNo">7034</span>      return storeHeap;<a name="line.7034"></a>
-<span class="sourceLineNo">7035</span>    }<a name="line.7035"></a>
-<span class="sourceLineNo">7036</span><a name="line.7036"></a>
-<span class="sourceLineNo">7037</span>    @Override<a name="line.7037"></a>
-<span class="sourceLineNo">7038</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7038"></a>
-<span class="sourceLineNo">7039</span>      if (row == null) {<a name="line.7039"></a>
-<span class="sourceLineNo">7040</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7040"></a>
-<span class="sourceLineNo">7041</span>      }<a name="line.7041"></a>
-<span class="sourceLineNo">7042</span>      boolean result = false;<a name="line.7042"></a>
-<span class="sourceLineNo">7043</span>      startRegionOperation();<a name="line.7043"></a>
-<span class="sourceLineNo">7044</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7044"></a>
-<span class="sourceLineNo">7045</span>      try {<a name="line.7045"></a>
-<span class="sourceLineNo">7046</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7046"></a>
-<span class="sourceLineNo">7047</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7047"></a>
-<span class="sourceLineNo">7048</span>        if (this.joinedHeap != null) {<a name="line.7048"></a>
-<span class="sourceLineNo">7049</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7049"></a>
-<span class="sourceLineNo">7050</span>        }<a name="line.7050"></a>
-<span class="sourceLineNo">7051</span>      } finally {<a name="line.7051"></a>
-<span class="sourceLineNo">7052</span>        closeRegionOperation();<a name="line.7052"></a>
-<span class="sourceLineNo">7053</span>      }<a name="line.7053"></a>
-<span class="sourceLineNo">7054</span>      return result;<a name="line.7054"></a>
-<span class="sourceLineNo">7055</span>    }<a name="line.7055"></a>
-<span class="sourceLineNo">7056</span><a name="line.7056"></a>
-<span class="sourceLineNo">7057</span>    @Override<a name="line.7057"></a>
-<span class="sourceLineNo">7058</span>    public void shipped() throws IOException {<a name="line.7058"></a>
-<span class="sourceLineNo">7059</span>      if (storeHeap != null) {<a name="line.7059"></a>
-<span class="sourceLineNo">7060</span>        storeHeap.shipped();<a name="line.7060"></a>
-<span class="sourceLineNo">7061</span>      }<a name="line.7061"></a>
-<span class="sourceLineNo">7062</span>      if (joinedHeap != null) {<a name="line.7062"></a>
-<span class="sourceLineNo">7063</span>        joinedHeap.shipped();<a name="line.7063"></a>
+<span class="sourceLineNo">7014</span>      if (stopRow == null || Bytes.equals(stopRow, HConstants.EMPTY_END_ROW)) {<a name="line.7014"></a>
+<span class="sourceLineNo">7015</span>        return false;<a name="line.7015"></a>
+<span class="sourceLineNo">7016</span>      }<a name="line.7016"></a>
+<span class="sourceLineNo">7017</span>      int c = comparator.compareRows(currentRowCell, stopRow, 0, stopRow.length);<a name="line.7017"></a>
+<span class="sourceLineNo">7018</span>      return c &gt; 0 || (c == 0 &amp;&amp; !includeStopRow);<a name="line.7018"></a>
+<span class="sourceLineNo">7019</span>    }<a name="line.7019"></a>
+<span class="sourceLineNo">7020</span><a name="line.7020"></a>
+<span class="sourceLineNo">7021</span>    @Override<a name="line.7021"></a>
+<span class="sourceLineNo">7022</span>    public synchronized void close() {<a name="line.7022"></a>
+<span class="sourceLineNo">7023</span>      if (storeHeap != null) {<a name="line.7023"></a>
+<span class="sourceLineNo">7024</span>        storeHeap.close();<a name="line.7024"></a>
+<span class="sourceLineNo">7025</span>        storeHeap = null;<a name="line.7025"></a>
+<span class="sourceLineNo">7026</span>      }<a name="line.7026"></a>
+<span class="sourceLineNo">7027</span>      if (joinedHeap != null) {<a name="line.7027"></a>
+<span class="sourceLineNo">7028</span>        joinedHeap.close();<a name="line.7028"></a>
+<span class="sourceLineNo">7029</span>        joinedHeap = null;<a name="line.7029"></a>
+<span class="sourceLineNo">7030</span>      }<a name="line.7030"></a>
+<span class="sourceLineNo">7031</span>      // no need to synchronize here.<a name="line.7031"></a>
+<span class="sourceLineNo">7032</span>      scannerReadPoints.remove(this);<a name="line.7032"></a>
+<span class="sourceLineNo">7033</span>      this.filterClosed = true;<a name="line.7033"></a>
+<span class="sourceLineNo">7034</span>    }<a name="line.7034"></a>
+<span class="sourceLineNo">7035</span><a name="line.7035"></a>
+<span class="sourceLineNo">7036</span>    KeyValueHeap getStoreHeapForTesting() {<a name="line.7036"></a>
+<span class="sourceLineNo">7037</span>      return storeHeap;<a name="line.7037"></a>
+<span class="sourceLineNo">7038</span>    }<a name="line.7038"></a>
+<span class="sourceLineNo">7039</span><a name="line.7039"></a>
+<span class="sourceLineNo">7040</span>    @Override<a name="line.7040"></a>
+<span class="sourceLineNo">7041</span>    public synchronized boolean reseek(byte[] row) throws IOException {<a name="line.7041"></a>
+<span class="sourceLineNo">7042</span>      if (row == null) {<a name="line.7042"></a>
+<span class="sourceLineNo">7043</span>        throw new IllegalArgumentException("Row cannot be null.");<a name="line.7043"></a>
+<span class="sourceLineNo">7044</span>      }<a name="line.7044"></a>
+<span class="sourceLineNo">7045</span>      boolean result = false;<a name="line.7045"></a>
+<span class="sourceLineNo">7046</span>      startRegionOperation();<a name="line.7046"></a>
+<span class="sourceLineNo">7047</span>      Cell kv = PrivateCellUtil.createFirstOnRow(row, 0, (short) row.length);<a name="line.7047"></a>
+<span class="sourceLineNo">7048</span>      try {<a name="line.7048"></a>
+<span class="sourceLineNo">7049</span>        // use request seek to make use of the lazy seek option. See HBASE-5520<a name="line.7049"></a>
+<span class="sourceLineNo">7050</span>        result = this.storeHeap.requestSeek(kv, true, true);<a name="line.7050"></a>
+<span class="sourceLineNo">7051</span>        if (this.joinedHeap != null) {<a name="line.7051"></a>
+<span class="sourceLineNo">7052</span>          result = this.joinedHeap.requestSeek(kv, true, true) || result;<a name="line.7052"></a>
+<span class="sourceLineNo">7053</span>        }<a name="line.7053"></a>
+<span class="sourceLineNo">7054</span>      } finally {<a name="line.7054"></a>
+<span class="sourceLineNo">7055</span>        closeRegionOperation();<a name="line.7055"></a>
+<span class="sourceLineNo">7056</span>      }<a name="line.7056"></a>
+<span class="sourceLineNo">7057</span>      return result;<a name="line.7057"></a>
+<span class="sourceLineNo">7058</span>    }<a name="line.7058"></a>
+<span class="sourceLineNo">7059</span><a name="line.7059"></a>
+<span class="sourceLineNo">7060</span>    @Override<a name="line.7060"></a>
+<span class="sourceLineNo">7061</span>    public void shipped() throws IOException {<a name="line.7061"></a>
+<span class="sourceLineNo">7062</span>      if (storeHeap != null) {<a name="line.7062"></a>
+<span class="sourceLineNo">7063</span>        storeHeap.shipped();<a name="line.7063"></a>
 <span class="sourceLineNo">7064</span>      }<a name="line.7064"></a>
-<span class="sourceLineNo">7065</span>    }<a name="line.7065"></a>
-<span class="sourceLineNo">7066</span><a name="line.7066"></a>
-<span class="sourceLineNo">7067</span>    @Override<a name="line.7067"></a>
-<span class="sourceLineNo">7068</span>    public void run() throws IOException {<a name="line.7068"></a>
-<span class="sourceLineNo">7069</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7069"></a>
-<span class="sourceLineNo">7070</span>      // callback<a name="line.7070"></a>
-<span class="sourceLineNo">7071</span>      this.close();<a name="line.7071"></a>
-<span class="sourceLineNo">7072</span>    }<a name="line.7072"></a>
-<span class="sourceLineNo">7073</span>  }<a name="line.7073"></a>
-<span class="sourceLineNo">7074</span><a name="line.7074"></a>
-<span class="sourceLineNo">7075</span>  // Utility methods<a name="line.7075"></a>
-<span class="sourceLineNo">7076</span>  /**<a name="line.7076"></a>
-<span class="sourceLineNo">7077</span>   * A utility method to create new instances of HRegion based on the<a name="line.7077"></a>
-<span class="sourceLineNo">7078</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7078"></a>
-<span class="sourceLineNo">7079</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7079"></a>
-<span class="sourceLineNo">7080</span>   * usually the table directory.<a name="line.7080"></a>
-<span class="sourceLineNo">7081</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7081"></a>
-<span class="sourceLineNo">7082</span>   * The wal file is a logfile from the previous execution that's<a name="line.7082"></a>
-<span class="sourceLineNo">7083</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7083"></a>
-<span class="sourceLineNo">7084</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7084"></a>
-<span class="sourceLineNo">7085</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7085"></a>
-<span class="sourceLineNo">7086</span>   * the supplied path.<a name="line.7086"></a>
-<span class="sourceLineNo">7087</span>   * @param fs is the filesystem.<a name="line.7087"></a>
-<span class="sourceLineNo">7088</span>   * @param conf is global configuration settings.<a name="line.7088"></a>
-<span class="sourceLineNo">7089</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7089"></a>
-<span class="sourceLineNo">7090</span>   * is new), then read them from the supplied path.<a name="line.7090"></a>
-<span class="sourceLineNo">7091</span>   * @param htd the table descriptor<a name="line.7091"></a>
-<span class="sourceLineNo">7092</span>   * @return the new instance<a name="line.7092"></a>
-<span class="sourceLineNo">7093</span>   */<a name="line.7093"></a>
-<span class="sourceLineNo">7094</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7094"></a>
-<span class="sourceLineNo">7095</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7095"></a>
-<span class="sourceLineNo">7096</span>      RegionServerServices rsServices) {<a name="line.7096"></a>
-<span class="sourceLineNo">7097</span>    try {<a name="line.7097"></a>
-<span class="sourceLineNo">7098</span>      @SuppressWarnings("unchecked")<a name="line.7098"></a>
-<span class="sourceLineNo">7099</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7099"></a>
-<span class="sourceLineNo">7100</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7100"></a>
-<span class="sourceLineNo">7101</span><a name="line.7101"></a>
-<span class="sourceLineNo">7102</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7102"></a>
-<span class="sourceLineNo">7103</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7103"></a>
-<span class="sourceLineNo">7104</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7104"></a>
-<span class="sourceLineNo">7105</span>              RegionServerServices.class);<a name="line.7105"></a>
-<span class="sourceLineNo">7106</span><a name="line.7106"></a>
-<span class="sourceLineNo">7107</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7107"></a>
-<span class="sourceLineNo">7108</span>    } catch (Throwable e) {<a name="line.7108"></a>
-<span class="sourceLineNo">7109</span>      // todo: what should I throw here?<a name="line.7109"></a>
-<span class="sourceLineNo">7110</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7110"></a>
-<span class="sourceLineNo">7111</span>    }<a name="line.7111"></a>
-<span class="sourceLineNo">7112</span>  }<a name="line.7112"></a>
-<span class="sourceLineNo">7113</span><a name="line.7113"></a>
-<span class="sourceLineNo">7114</span>  /**<a name="line.7114"></a>
-<span class="sourceLineNo">7115</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7115"></a>
-<span class="sourceLineNo">7116</span>   *<a name="line.7116"></a>
-<span class="sourceLineNo">7117</span>   * @param info Info for region to create.<a name="line.7117"></a>
-<span class="sourceLineNo">7118</span>   * @param rootDir Root directory for HBase instance<a name="line.7118"></a>
-<span class="sourceLineNo">7119</span>   * @param wal shared WAL<a name="line.7119"></a>
-<span class="sourceLineNo">7120</span>   * @param initialize - true to initialize the region<a name="line.7120"></a>
-<span class="sourceLineNo">7121</span>   * @return new HRegion<a name="line.7121"></a>
-<span class="sourceLineNo">7122</span>   * @throws IOException<a name="line.7122"></a>
-<span class="sourceLineNo">7123</span>   */<a name="line.7123"></a>
-<span class="sourceLineNo">7124</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7124"></a>
-<span class="sourceLineNo">7125</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7125"></a>
-<span class="sourceLineNo">7126</span>        final WAL wal, final boolean initialize)<a name="line.7126"></a>
-<span class="sourceLineNo">7127</span>  throws IOException {<a name="line.7127"></a>
-<span class="sourceLineNo">7128</span>    LOG.info("creating " + info<a name="line.7128"></a>
-<span class="sourceLineNo">7129</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7129"></a>
-<span class="sourceLineNo">7130</span>        ", regionDir=" + rootDir);<a name="line.7130"></a>
-<span class="sourceLineNo">7131</span>    createRegionDir(conf, info, rootDir);<a name="line.7131"></a>
-<span class="sourceLineNo">7132</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7132"></a>
-<span class="sourceLineNo">7133</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7133"></a>
-<span class="sourceLineNo">7134</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7134"></a>
-<span class="sourceLineNo">7135</span>    if (initialize) {<a name="line.7135"></a>
-<span class="sourceLineNo">7136</span>      region.initialize(null);<a name="line.7136"></a>
-<span class="sourceLineNo">7137</span>    }<a name="line.7137"></a>
-<span class="sourceLineNo">7138</span>    return region;<a name="line.7138"></a>
-<span class="sourceLineNo">7139</span>  }<a name="line.7139"></a>
-<span class="sourceLineNo">7140</span><a name="line.7140"></a>
-<span class="sourceLineNo">7141</span>  /**<a name="line.7141"></a>
-<span class="sourceLineNo">7142</span>   * Create the region directory in the filesystem.<a name="line.7142"></a>
-<span class="sourceLineNo">7143</span>   */<a name="line.7143"></a>
-<span class="sourceLineNo">7144</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7144"></a>
-<span class="sourceLineNo">7145</span>        Path rootDir)<a name="line.7145"></a>
-<span class="sourceLineNo">7146</span>      throws IOException {<a name="line.7146"></a>
-<span class="sourceLineNo">7147</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7147"></a>
-<span class="sourceLineNo">7148</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7148"></a>
-<span class="sourceLineNo">7149</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7149"></a>
-<span class="sourceLineNo">7150</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7150"></a>
-<span class="sourceLineNo">7151</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7151"></a>
-<span class="sourceLineNo">7152</span>  }<a name="line.7152"></a>
-<span class="sourceLineNo">7153</span><a name="line.7153"></a>
-<span class="sourceLineNo">7154</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7154"></a>
-<span class="sourceLineNo">7155</span>                                      final Configuration conf,<a name="line.7155"></a>
-<span class="sourceLineNo">7156</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7156"></a>
-<span class="sourceLineNo">7157</span>                                      final WAL wal)<a name="line.7157"></a>
-<span class="sourceLineNo">7158</span>    throws IOException {<a name="line.7158"></a>
-<span class="sourceLineNo">7159</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7159"></a>
-<span class="sourceLineNo">7160</span>  }<a name="line.7160"></a>
-<span class="sourceLineNo">7161</span><a name="line.7161"></a>
-<span class="sourceLineNo">7162</span><a name="line.7162"></a>
-<span class="sourceLineNo">7163</span>  /**<a name="line.7163"></a>
-<span class="sourceLineNo">7164</span>   * Open a Region.<a name="line.7164"></a>
-<span class="sourceLineNo">7165</span>   * @param info Info for region to be opened.<a name="line.7165"></a>
-<span class="sourceLineNo">7166</span>   * @param wal WAL for region to use. This method will call<a name="line.7166"></a>
-<span class="sourceLineNo">7167</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7167"></a>
-<span class="sourceLineNo">7168</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7168"></a>
-<span class="sourceLineNo">7169</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7169"></a>
-<span class="sourceLineNo">7170</span>   * @return new HRegion<a name="line.7170"></a>
-<span class="sourceLineNo">7171</span>   *<a name="line.7171"></a>
-<span class="sourceLineNo">7172</span>   * @throws IOException<a name="line.7172"></a>
-<span class="sourceLineNo">7173</span>   */<a name="line.7173"></a>
-<span class="sourceLineNo">7174</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7174"></a>
-<span class="sourceLineNo">7175</span>      final TableDescriptor htd, final WAL wal,<a name="line.7175"></a>
-<span class="sourceLineNo">7176</span>      final Configuration conf)<a name="line.7176"></a>
-<span class="sourceLineNo">7177</span>  throws IOException {<a name="line.7177"></a>
-<span class="sourceLineNo">7178</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7178"></a>
-<span class="sourceLineNo">7179</span>  }<a name="line.7179"></a>
-<span class="sourceLineNo">7180</span><a name="line.7180"></a>
-<span class="sourceLineNo">7181</span>  /**<a name="line.7181"></a>
-<span class="sourceLineNo">7182</span>   * Open a Region.<a name="line.7182"></a>
-<span class="sourceLineNo">7183</span>   * @param info Info for region to be opened<a name="line.7183"></a>
-<span class="sourceLineNo">7184</span>   * @param htd the table descriptor<a name="line.7184"></a>
-<span class="sourceLineNo">7185</span>   * @param wal WAL for region to use. This method will call<a name="line.7185"></a>
-<span class="sourceLineNo">7186</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7186"></a>
-<span class="sourceLineNo">7187</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7187"></a>
-<span class="sourceLineNo">7188</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7188"></a>
-<span class="sourceLineNo">7189</span>   * @param conf The Configuration object to use.<a name="line.7189"></a>
-<span class="sourceLineNo">7190</span>   * @param rsServices An interface we can request flushes against.<a name="line.7190"></a>
-<span class="sourceLineNo">7191</span>   * @param reporter An interface we can report progress against.<a name="line.7191"></a>
-<span class="sourceLineNo">7192</span>   * @return new HRegion<a name="line.7192"></a>
-<span class="sourceLineNo">7193</span>   *<a name="line.7193"></a>
-<span class="sourceLineNo">7194</span>   * @throws IOException<a name="line.7194"></a>
-<span class="sourceLineNo">7195</span>   */<a name="line.7195"></a>
-<span class="sourceLineNo">7196</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7196"></a>
-<span class="sourceLineNo">7197</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7197"></a>
-<span class="sourceLineNo">7198</span>    final RegionServerServices rsServices,<a name="line.7198"></a>
-<span class="sourceLineNo">7199</span>    final CancelableProgressable reporter)<a name="line.7199"></a>
-<span class="sourceLineNo">7200</span>  throws IOException {<a name="line.7200"></a>
-<span class="sourceLineNo">7201</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7201"></a>
-<span class="sourceLineNo">7202</span>  }<a name="line.7202"></a>
-<span class="sourceLineNo">7203</span><a name="line.7203"></a>
-<span class="sourceLineNo">7204</span>  /**<a name="line.7204"></a>
-<span class="sourceLineNo">7205</span>   * Open a Region.<a name="line.7205"></a>
-<span class="sourceLineNo">7206</span>   * @param rootDir Root directory for HBase instance<a name="line.7206"></a>
-<span class="sourceLineNo">7207</span>   * @param info Info for region to be opened.<a name="line.7207"></a>
-<span class="sourceLineNo">7208</span>   * @param htd the table descriptor<a name="line.7208"></a>
-<span class="sourceLineNo">7209</span>   * @param wal WAL for region to use. This method will call<a name="line.7209"></a>
-<span class="sourceLineNo">7210</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7210"></a>
-<span class="sourceLineNo">7211</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7211"></a>
-<span class="sourceLineNo">7212</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7212"></a>
-<span class="sourceLineNo">7213</span>   * @param conf The Configuration object to use.<a name="line.7213"></a>
-<span class="sourceLineNo">7214</span>   * @return new HRegion<a name="line.7214"></a>
-<span class="sourceLineNo">7215</span>   * @throws IOException<a name="line.7215"></a>
-<span class="sourceLineNo">7216</span>   */<a name="line.7216"></a>
-<span class="sourceLineNo">7217</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7217"></a>
-<span class="sourceLineNo">7218</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7218"></a>
-<span class="sourceLineNo">7219</span>  throws IOException {<a name="line.7219"></a>
-<span class="sourceLineNo">7220</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7220"></a>
-<span class="sourceLineNo">7221</span>  }<a name="line.7221"></a>
-<span class="sourceLineNo">7222</span><a name="line.7222"></a>
-<span class="sourceLineNo">7223</span>  /**<a name="line.7223"></a>
-<span class="sourceLineNo">7224</span>   * Open a Region.<a name="line.7224"></a>
-<span class="sourceLineNo">7225</span>   * @param rootDir Root directory for HBase instance<a name="line.7225"></a>
-<span class="sourceLineNo">7226</span>   * @param info Info for region to be opened.<a name="line.7226"></a>
-<span class="sourceLineNo">7227</span>   * @param htd the table descriptor<a name="line.7227"></a>
-<span class="sourceLineNo">7228</span>   * @param wal WAL for region to use. This method will call<a name="line.7228"></a>
-<span class="sourceLineNo">7229</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7229"></a>
-<span class="sourceLineNo">7230</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7230"></a>
-<span class="sourceLineNo">7231</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7231"></a>
-<span class="sourceLineNo">7232</span>   * @param conf The Configuration object to use.<a name="line.7232"></a>
-<span class="sourceLineNo">7233</span>   * @param rsServices An interface we can request flushes against.<a name="line.7233"></a>
-<span class="sourceLineNo">7234</span>   * @param reporter An interface we can report progress against.<a name="line.7234"></a>
-<span class="sourceLineNo">7235</span>   * @return new HRegion<a name="line.7235"></a>
-<span class="sourceLineNo">7236</span>   * @throws IOException<a name="line.7236"></a>
-<span class="sourceLineNo">7237</span>   */<a name="line.7237"></a>
-<span class="sourceLineNo">7238</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7238"></a>
-<span class="sourceLineNo">7239</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7239"></a>
-<span class="sourceLineNo">7240</span>      final RegionServerServices rsServices,<a name="line.7240"></a>
-<span class="sourceLineNo">7241</span>      final CancelableProgressable reporter)<a name="line.7241"></a>
-<span class="sourceLineNo">7242</span>  throws IOException {<a name="line.7242"></a>
-<span class="sourceLineNo">7243</span>    FileSystem fs = null;<a name="line.7243"></a>
-<span class="sourceLineNo">7244</span>    if (rsServices != null) {<a name="line.7244"></a>
-<span class="sourceLineNo">7245</span>      fs = rsServices.getFileSystem();<a name="line.7245"></a>
-<span class="sourceLineNo">7246</span>    }<a name="line.7246"></a>
-<span class="sourceLineNo">7247</span>    if (fs == null) {<a name="line.7247"></a>
-<span class="sourceLineNo">7248</span>      fs = rootDir.getFileSystem(conf);<a name="line.7248"></a>
+<span class="sourceLineNo">7065</span>      if (joinedHeap != null) {<a name="line.7065"></a>
+<span class="sourceLineNo">7066</span>        joinedHeap.shipped();<a name="line.7066"></a>
+<span class="sourceLineNo">7067</span>      }<a name="line.7067"></a>
+<span class="sourceLineNo">7068</span>    }<a name="line.7068"></a>
+<span class="sourceLineNo">7069</span><a name="line.7069"></a>
+<span class="sourceLineNo">7070</span>    @Override<a name="line.7070"></a>
+<span class="sourceLineNo">7071</span>    public void run() throws IOException {<a name="line.7071"></a>
+<span class="sourceLineNo">7072</span>      // This is the RPC callback method executed. We do the close in of the scanner in this<a name="line.7072"></a>
+<span class="sourceLineNo">7073</span>      // callback<a name="line.7073"></a>
+<span class="sourceLineNo">7074</span>      this.close();<a name="line.7074"></a>
+<span class="sourceLineNo">7075</span>    }<a name="line.7075"></a>
+<span class="sourceLineNo">7076</span>  }<a name="line.7076"></a>
+<span class="sourceLineNo">7077</span><a name="line.7077"></a>
+<span class="sourceLineNo">7078</span>  // Utility methods<a name="line.7078"></a>
+<span class="sourceLineNo">7079</span>  /**<a name="line.7079"></a>
+<span class="sourceLineNo">7080</span>   * A utility method to create new instances of HRegion based on the<a name="line.7080"></a>
+<span class="sourceLineNo">7081</span>   * {@link HConstants#REGION_IMPL} configuration property.<a name="line.7081"></a>
+<span class="sourceLineNo">7082</span>   * @param tableDir qualified path of directory where region should be located,<a name="line.7082"></a>
+<span class="sourceLineNo">7083</span>   * usually the table directory.<a name="line.7083"></a>
+<span class="sourceLineNo">7084</span>   * @param wal The WAL is the outbound log for any updates to the HRegion<a name="line.7084"></a>
+<span class="sourceLineNo">7085</span>   * The wal file is a logfile from the previous execution that's<a name="line.7085"></a>
+<span class="sourceLineNo">7086</span>   * custom-computed for this HRegion. The HRegionServer computes and sorts the<a name="line.7086"></a>
+<span class="sourceLineNo">7087</span>   * appropriate wal info for this HRegion. If there is a previous file<a name="line.7087"></a>
+<span class="sourceLineNo">7088</span>   * (implying that the HRegion has been written-to before), then read it from<a name="line.7088"></a>
+<span class="sourceLineNo">7089</span>   * the supplied path.<a name="line.7089"></a>
+<span class="sourceLineNo">7090</span>   * @param fs is the filesystem.<a name="line.7090"></a>
+<span class="sourceLineNo">7091</span>   * @param conf is global configuration settings.<a name="line.7091"></a>
+<span class="sourceLineNo">7092</span>   * @param regionInfo - RegionInfo that describes the region<a name="line.7092"></a>
+<span class="sourceLineNo">7093</span>   * is new), then read them from the supplied path.<a name="line.7093"></a>
+<span class="sourceLineNo">7094</span>   * @param htd the table descriptor<a name="line.7094"></a>
+<span class="sourceLineNo">7095</span>   * @return the new instance<a name="line.7095"></a>
+<span class="sourceLineNo">7096</span>   */<a name="line.7096"></a>
+<span class="sourceLineNo">7097</span>  public static HRegion newHRegion(Path tableDir, WAL wal, FileSystem fs,<a name="line.7097"></a>
+<span class="sourceLineNo">7098</span>      Configuration conf, RegionInfo regionInfo, final TableDescriptor htd,<a name="line.7098"></a>
+<span class="sourceLineNo">7099</span>      RegionServerServices rsServices) {<a name="line.7099"></a>
+<span class="sourceLineNo">7100</span>    try {<a name="line.7100"></a>
+<span class="sourceLineNo">7101</span>      @SuppressWarnings("unchecked")<a name="line.7101"></a>
+<span class="sourceLineNo">7102</span>      Class&lt;? extends HRegion&gt; regionClass =<a name="line.7102"></a>
+<span class="sourceLineNo">7103</span>          (Class&lt;? extends HRegion&gt;) conf.getClass(HConstants.REGION_IMPL, HRegion.class);<a name="line.7103"></a>
+<span class="sourceLineNo">7104</span><a name="line.7104"></a>
+<span class="sourceLineNo">7105</span>      Constructor&lt;? extends HRegion&gt; c =<a name="line.7105"></a>
+<span class="sourceLineNo">7106</span>          regionClass.getConstructor(Path.class, WAL.class, FileSystem.class,<a name="line.7106"></a>
+<span class="sourceLineNo">7107</span>              Configuration.class, RegionInfo.class, TableDescriptor.class,<a name="line.7107"></a>
+<span class="sourceLineNo">7108</span>              RegionServerServices.class);<a name="line.7108"></a>
+<span class="sourceLineNo">7109</span><a name="line.7109"></a>
+<span class="sourceLineNo">7110</span>      return c.newInstance(tableDir, wal, fs, conf, regionInfo, htd, rsServices);<a name="line.7110"></a>
+<span class="sourceLineNo">7111</span>    } catch (Throwable e) {<a name="line.7111"></a>
+<span class="sourceLineNo">7112</span>      // todo: what should I throw here?<a name="line.7112"></a>
+<span class="sourceLineNo">7113</span>      throw new IllegalStateException("Could not instantiate a region instance.", e);<a name="line.7113"></a>
+<span class="sourceLineNo">7114</span>    }<a name="line.7114"></a>
+<span class="sourceLineNo">7115</span>  }<a name="line.7115"></a>
+<span class="sourceLineNo">7116</span><a name="line.7116"></a>
+<span class="sourceLineNo">7117</span>  /**<a name="line.7117"></a>
+<span class="sourceLineNo">7118</span>   * Convenience method creating new HRegions. Used by createTable.<a name="line.7118"></a>
+<span class="sourceLineNo">7119</span>   *<a name="line.7119"></a>
+<span class="sourceLineNo">7120</span>   * @param info Info for region to create.<a name="line.7120"></a>
+<span class="sourceLineNo">7121</span>   * @param rootDir Root directory for HBase instance<a name="line.7121"></a>
+<span class="sourceLineNo">7122</span>   * @param wal shared WAL<a name="line.7122"></a>
+<span class="sourceLineNo">7123</span>   * @param initialize - true to initialize the region<a name="line.7123"></a>
+<span class="sourceLineNo">7124</span>   * @return new HRegion<a name="line.7124"></a>
+<span class="sourceLineNo">7125</span>   * @throws IOException<a name="line.7125"></a>
+<span class="sourceLineNo">7126</span>   */<a name="line.7126"></a>
+<span class="sourceLineNo">7127</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7127"></a>
+<span class="sourceLineNo">7128</span>        final Configuration conf, final TableDescriptor hTableDescriptor,<a name="line.7128"></a>
+<span class="sourceLineNo">7129</span>        final WAL wal, final boolean initialize)<a name="line.7129"></a>
+<span class="sourceLineNo">7130</span>  throws IOException {<a name="line.7130"></a>
+<span class="sourceLineNo">7131</span>    LOG.info("creating " + info<a name="line.7131"></a>
+<span class="sourceLineNo">7132</span>        + ", tableDescriptor=" + (hTableDescriptor == null? "null": hTableDescriptor) +<a name="line.7132"></a>
+<span class="sourceLineNo">7133</span>        ", regionDir=" + rootDir);<a name="line.7133"></a>
+<span class="sourceLineNo">7134</span>    createRegionDir(conf, info, rootDir);<a name="line.7134"></a>
+<span class="sourceLineNo">7135</span>    FileSystem fs = rootDir.getFileSystem(conf);<a name="line.7135"></a>
+<span class="sourceLineNo">7136</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7136"></a>
+<span class="sourceLineNo">7137</span>    HRegion region = HRegion.newHRegion(tableDir, wal, fs, conf, info, hTableDescriptor, null);<a name="line.7137"></a>
+<span class="sourceLineNo">7138</span>    if (initialize) {<a name="line.7138"></a>
+<span class="sourceLineNo">7139</span>      region.initialize(null);<a name="line.7139"></a>
+<span class="sourceLineNo">7140</span>    }<a name="line.7140"></a>
+<span class="sourceLineNo">7141</span>    return region;<a name="line.7141"></a>
+<span class="sourceLineNo">7142</span>  }<a name="line.7142"></a>
+<span class="sourceLineNo">7143</span><a name="line.7143"></a>
+<span class="sourceLineNo">7144</span>  /**<a name="line.7144"></a>
+<span class="sourceLineNo">7145</span>   * Create the region directory in the filesystem.<a name="line.7145"></a>
+<span class="sourceLineNo">7146</span>   */<a name="line.7146"></a>
+<span class="sourceLineNo">7147</span>  public static HRegionFileSystem createRegionDir(Configuration configuration, RegionInfo ri,<a name="line.7147"></a>
+<span class="sourceLineNo">7148</span>        Path rootDir)<a name="line.7148"></a>
+<span class="sourceLineNo">7149</span>      throws IOException {<a name="line.7149"></a>
+<span class="sourceLineNo">7150</span>    FileSystem fs = rootDir.getFileSystem(configuration);<a name="line.7150"></a>
+<span class="sourceLineNo">7151</span>    Path tableDir = FSUtils.getTableDir(rootDir, ri.getTable());<a name="line.7151"></a>
+<span class="sourceLineNo">7152</span>    // If directory already exists, will log warning and keep going. Will try to create<a name="line.7152"></a>
+<span class="sourceLineNo">7153</span>    // .regioninfo. If one exists, will overwrite.<a name="line.7153"></a>
+<span class="sourceLineNo">7154</span>    return HRegionFileSystem.createRegionOnFileSystem(configuration, fs, tableDir, ri);<a name="line.7154"></a>
+<span class="sourceLineNo">7155</span>  }<a name="line.7155"></a>
+<span class="sourceLineNo">7156</span><a name="line.7156"></a>
+<span class="sourceLineNo">7157</span>  public static HRegion createHRegion(final RegionInfo info, final Path rootDir,<a name="line.7157"></a>
+<span class="sourceLineNo">7158</span>                                      final Configuration conf,<a name="line.7158"></a>
+<span class="sourceLineNo">7159</span>                                      final TableDescriptor hTableDescriptor,<a name="line.7159"></a>
+<span class="sourceLineNo">7160</span>                                      final WAL wal)<a name="line.7160"></a>
+<span class="sourceLineNo">7161</span>    throws IOException {<a name="line.7161"></a>
+<span class="sourceLineNo">7162</span>    return createHRegion(info, rootDir, conf, hTableDescriptor, wal, true);<a name="line.7162"></a>
+<span class="sourceLineNo">7163</span>  }<a name="line.7163"></a>
+<span class="sourceLineNo">7164</span><a name="line.7164"></a>
+<span class="sourceLineNo">7165</span><a name="line.7165"></a>
+<span class="sourceLineNo">7166</span>  /**<a name="line.7166"></a>
+<span class="sourceLineNo">7167</span>   * Open a Region.<a name="line.7167"></a>
+<span class="sourceLineNo">7168</span>   * @param info Info for region to be opened.<a name="line.7168"></a>
+<span class="sourceLineNo">7169</span>   * @param wal WAL for region to use. This method will call<a name="line.7169"></a>
+<span class="sourceLineNo">7170</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7170"></a>
+<span class="sourceLineNo">7171</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7171"></a>
+<span class="sourceLineNo">7172</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7172"></a>
+<span class="sourceLineNo">7173</span>   * @return new HRegion<a name="line.7173"></a>
+<span class="sourceLineNo">7174</span>   *<a name="line.7174"></a>
+<span class="sourceLineNo">7175</span>   * @throws IOException<a name="line.7175"></a>
+<span class="sourceLineNo">7176</span>   */<a name="line.7176"></a>
+<span class="sourceLineNo">7177</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7177"></a>
+<span class="sourceLineNo">7178</span>      final TableDescriptor htd, final WAL wal,<a name="line.7178"></a>
+<span class="sourceLineNo">7179</span>      final Configuration conf)<a name="line.7179"></a>
+<span class="sourceLineNo">7180</span>  throws IOException {<a name="line.7180"></a>
+<span class="sourceLineNo">7181</span>    return openHRegion(info, htd, wal, conf, null, null);<a name="line.7181"></a>
+<span class="sourceLineNo">7182</span>  }<a name="line.7182"></a>
+<span class="sourceLineNo">7183</span><a name="line.7183"></a>
+<span class="sourceLineNo">7184</span>  /**<a name="line.7184"></a>
+<span class="sourceLineNo">7185</span>   * Open a Region.<a name="line.7185"></a>
+<span class="sourceLineNo">7186</span>   * @param info Info for region to be opened<a name="line.7186"></a>
+<span class="sourceLineNo">7187</span>   * @param htd the table descriptor<a name="line.7187"></a>
+<span class="sourceLineNo">7188</span>   * @param wal WAL for region to use. This method will call<a name="line.7188"></a>
+<span class="sourceLineNo">7189</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7189"></a>
+<span class="sourceLineNo">7190</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7190"></a>
+<span class="sourceLineNo">7191</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7191"></a>
+<span class="sourceLineNo">7192</span>   * @param conf The Configuration object to use.<a name="line.7192"></a>
+<span class="sourceLineNo">7193</span>   * @param rsServices An interface we can request flushes against.<a name="line.7193"></a>
+<span class="sourceLineNo">7194</span>   * @param reporter An interface we can report progress against.<a name="line.7194"></a>
+<span class="sourceLineNo">7195</span>   * @return new HRegion<a name="line.7195"></a>
+<span class="sourceLineNo">7196</span>   *<a name="line.7196"></a>
+<span class="sourceLineNo">7197</span>   * @throws IOException<a name="line.7197"></a>
+<span class="sourceLineNo">7198</span>   */<a name="line.7198"></a>
+<span class="sourceLineNo">7199</span>  public static HRegion openHRegion(final RegionInfo info,<a name="line.7199"></a>
+<span class="sourceLineNo">7200</span>    final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7200"></a>
+<span class="sourceLineNo">7201</span>    final RegionServerServices rsServices,<a name="line.7201"></a>
+<span class="sourceLineNo">7202</span>    final CancelableProgressable reporter)<a name="line.7202"></a>
+<span class="sourceLineNo">7203</span>  throws IOException {<a name="line.7203"></a>
+<span class="sourceLineNo">7204</span>    return openHRegion(FSUtils.getRootDir(conf), info, htd, wal, conf, rsServices, reporter);<a name="line.7204"></a>
+<span class="sourceLineNo">7205</span>  }<a name="line.7205"></a>
+<span class="sourceLineNo">7206</span><a name="line.7206"></a>
+<span class="sourceLineNo">7207</span>  /**<a name="line.7207"></a>
+<span class="sourceLineNo">7208</span>   * Open a Region.<a name="line.7208"></a>
+<span class="sourceLineNo">7209</span>   * @param rootDir Root directory for HBase instance<a name="line.7209"></a>
+<span class="sourceLineNo">7210</span>   * @param info Info for region to be opened.<a name="line.7210"></a>
+<span class="sourceLineNo">7211</span>   * @param htd the table descriptor<a name="line.7211"></a>
+<span class="sourceLineNo">7212</span>   * @param wal WAL for region to use. This method will call<a name="line.7212"></a>
+<span class="sourceLineNo">7213</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7213"></a>
+<span class="sourceLineNo">7214</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7214"></a>
+<span class="sourceLineNo">7215</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7215"></a>
+<span class="sourceLineNo">7216</span>   * @param conf The Configuration object to use.<a name="line.7216"></a>
+<span class="sourceLineNo">7217</span>   * @return new HRegion<a name="line.7217"></a>
+<span class="sourceLineNo">7218</span>   * @throws IOException<a name="line.7218"></a>
+<span class="sourceLineNo">7219</span>   */<a name="line.7219"></a>
+<span class="sourceLineNo">7220</span>  public static HRegion openHRegion(Path rootDir, final RegionInfo info,<a name="line.7220"></a>
+<span class="sourceLineNo">7221</span>      final TableDescriptor htd, final WAL wal, final Configuration conf)<a name="line.7221"></a>
+<span class="sourceLineNo">7222</span>  throws IOException {<a name="line.7222"></a>
+<span class="sourceLineNo">7223</span>    return openHRegion(rootDir, info, htd, wal, conf, null, null);<a name="line.7223"></a>
+<span class="sourceLineNo">7224</span>  }<a name="line.7224"></a>
+<span class="sourceLineNo">7225</span><a name="line.7225"></a>
+<span class="sourceLineNo">7226</span>  /**<a name="line.7226"></a>
+<span class="sourceLineNo">7227</span>   * Open a Region.<a name="line.7227"></a>
+<span class="sourceLineNo">7228</span>   * @param rootDir Root directory for HBase instance<a name="line.7228"></a>
+<span class="sourceLineNo">7229</span>   * @param info Info for region to be opened.<a name="line.7229"></a>
+<span class="sourceLineNo">7230</span>   * @param htd the table descriptor<a name="line.7230"></a>
+<span class="sourceLineNo">7231</span>   * @param wal WAL for region to use. This method will call<a name="line.7231"></a>
+<span class="sourceLineNo">7232</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7232"></a>
+<span class="sourceLineNo">7233</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7233"></a>
+<span class="sourceLineNo">7234</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7234"></a>
+<span class="sourceLineNo">7235</span>   * @param conf The Configuration object to use.<a name="line.7235"></a>
+<span class="sourceLineNo">7236</span>   * @param rsServices An interface we can request flushes against.<a name="line.7236"></a>
+<span class="sourceLineNo">7237</span>   * @param reporter An interface we can report progress against.<a name="line.7237"></a>
+<span class="sourceLineNo">7238</span>   * @return new HRegion<a name="line.7238"></a>
+<span class="sourceLineNo">7239</span>   * @throws IOException<a name="line.7239"></a>
+<span class="sourceLineNo">7240</span>   */<a name="line.7240"></a>
+<span class="sourceLineNo">7241</span>  public static HRegion openHRegion(final Path rootDir, final RegionInfo info,<a name="line.7241"></a>
+<span class="sourceLineNo">7242</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7242"></a>
+<span class="sourceLineNo">7243</span>      final RegionServerServices rsServices,<a name="line.7243"></a>
+<span class="sourceLineNo">7244</span>      final CancelableProgressable reporter)<a name="line.7244"></a>
+<span class="sourceLineNo">7245</span>  throws IOException {<a name="line.7245"></a>
+<span class="sourceLineNo">7246</span>    FileSystem fs = null;<a name="line.7246"></a>
+<span class="sourceLineNo">7247</span>    if (rsServices != null) {<a name="line.7247"></a>
+<span class="sourceLineNo">7248</span>      fs = rsServices.getFileSystem();<a name="line.7248"></a>
 <span class="sourceLineNo">7249</span>    }<a name="line.7249"></a>
-<span class="sourceLineNo">7250</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7250"></a>
-<span class="sourceLineNo">7251</span>  }<a name="line.7251"></a>
-<span class="sourceLineNo">7252</span><a name="line.7252"></a>
-<span class="sourceLineNo">7253</span>  /**<a name="line.7253"></a>
-<span class="sourceLineNo">7254</span>   * Open a Region.<a name="line.7254"></a>
-<span class="sourceLineNo">7255</span>   * @param conf The Configuration object to use.<a name="line.7255"></a>
-<span class="sourceLineNo">7256</span>   * @param fs Filesystem to use<a name="line.7256"></a>
-<span class="sourceLineNo">7257</span>   * @param rootDir Root directory for HBase instance<a name="line.7257"></a>
-<span class="sourceLineNo">7258</span>   * @param info Info for region to be opened.<a name="line.7258"></a>
-<span class="sourceLineNo">7259</span>   * @param htd the table descriptor<a name="line.7259"></a>
-<span class="sourceLineNo">7260</span>   * @param wal WAL for region to use. This method will call<a name="line.7260"></a>
-<span class="sourceLineNo">7261</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7261"></a>
-<span class="sourceLineNo">7262</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7262"></a>
-<span class="sourceLineNo">7263</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7263"></a>
-<span class="sourceLineNo">7264</span>   * @return new HRegion<a name="line.7264"></a>
-<span class="sourceLineNo">7265</span>   */<a name="line.7265"></a>
-<span class="sourceLineNo">7266</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7266"></a>
-<span class="sourceLineNo">7267</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7267"></a>
-<span class="sourceLineNo">7268</span>      throws IOException {<a name="line.7268"></a>
-<span class="sourceLineNo">7269</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7269"></a>
-<span class="sourceLineNo">7270</span>  }<a name="line.7270"></a>
-<span class="sourceLineNo">7271</span><a name="line.7271"></a>
-<span class="sourceLineNo">7272</span>  /**<a name="line.7272"></a>
-<span class="sourceLineNo">7273</span>   * Open a Region.<a name="line.7273"></a>
-<span class="sourceLineNo">7274</span>   * @param conf The Configuration object to use.<a name="line.7274"></a>
-<span class="sourceLineNo">7275</span>   * @param fs Filesystem to use<a name="line.7275"></a>
-<span class="sourceLineNo">7276</span>   * @param rootDir Root directory for HBase instance<a name="line.7276"></a>
-<span class="sourceLineNo">7277</span>   * @param info Info for region to be opened.<a name="line.7277"></a>
-<span class="sourceLineNo">7278</span>   * @param htd the table descriptor<a name="line.7278"></a>
-<span class="sourceLineNo">7279</span>   * @param wal WAL for region to use. This method will call<a name="line.7279"></a>
-<span class="sourceLineNo">7280</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7280"></a>
-<span class="sourceLineNo">7281</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7281"></a>
-<span class="sourceLineNo">7282</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7282"></a>
-<span class="sourceLineNo">7283</span>   * @param rsServices An interface we can request flushes against.<a name="line.7283"></a>
-<span class="sourceLineNo">7284</span>   * @param reporter An interface we can report progress against.<a name="line.7284"></a>
-<span class="sourceLineNo">7285</span>   * @return new HRegion<a name="line.7285"></a>
-<span class="sourceLineNo">7286</span>   */<a name="line.7286"></a>
-<span class="sourceLineNo">7287</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7287"></a>
-<span class="sourceLineNo">7288</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7288"></a>
-<span class="sourceLineNo">7289</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7289"></a>
-<span class="sourceLineNo">7290</span>      throws IOException {<a name="line.7290"></a>
-<span class="sourceLineNo">7291</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7291"></a>
-<span class="sourceLineNo">7292</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7292"></a>
-<span class="sourceLineNo">7293</span>  }<a name="line.7293"></a>
-<span class="sourceLineNo">7294</span><a name="line.7294"></a>
-<span class="sourceLineNo">7295</span>  /**<a name="line.7295"></a>
-<span class="sourceLineNo">7296</span>   * Open a Region.<a name="line.7296"></a>
-<span class="sourceLineNo">7297</span>   * @param conf The Configuration object to use.<a name="line.7297"></a>
-<span class="sourceLineNo">7298</span>   * @param fs Filesystem to use<a name="line.7298"></a>
-<span class="sourceLineNo">7299</span>   * @param rootDir Root directory for HBase instance<a name="line.7299"></a>
-<span class="sourceLineNo">7300</span>   * @param info Info for region to be opened.<a name="line.7300"></a>
-<span class="sourceLineNo">7301</span>   * @param htd the table descriptor<a name="line.7301"></a>
-<span class="sourceLineNo">7302</span>   * @param wal WAL for region to use. This method will call<a name="line.7302"></a>
-<span class="sourceLineNo">7303</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7303"></a>
-<span class="sourceLineNo">7304</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7304"></a>
-<span class="sourceLineNo">7305</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7305"></a>
-<span class="sourceLineNo">7306</span>   * @param rsServices An interface we can request flushes against.<a name="line.7306"></a>
-<span class="sourceLineNo">7307</span>   * @param reporter An interface we can report progress against.<a name="line.7307"></a>
-<span class="sourceLineNo">7308</span>   * @return new HRegion<a name="line.7308"></a>
-<span class="sourceLineNo">7309</span>   */<a name="line.7309"></a>
-<span class="sourceLineNo">7310</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7310"></a>
-<span class="sourceLineNo">7311</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7311"></a>
-<span class="sourceLineNo">7312</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7312"></a>
-<span class="sourceLineNo">7313</span>      final CancelableProgressable reporter)<a name="line.7313"></a>
-<span class="sourceLineNo">7314</span>      throws IOException {<a name="line.7314"></a>
-<span class="sourceLineNo">7315</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7315"></a>
-<span class="sourceLineNo">7316</span>    if (LOG.isDebugEnabled()) {<a name="line.7316"></a>
-<span class="sourceLineNo">7317</span>      LOG.debug("Opening region: " + info);<a name="line.7317"></a>
-<span class="sourceLineNo">7318</span>    }<a name="line.7318"></a>
-<span class="sourceLineNo">7319</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7319"></a>
-<span class="sourceLineNo">7320</span>    return r.openHRegion(reporter);<a name="line.7320"></a>
-<span class="sourceLineNo">7321</span>  }<a name="line.7321"></a>
-<span class="sourceLineNo">7322</span><a name="line.7322"></a>
-<span class="sourceLineNo">7323</span>  @VisibleForTesting<a name="line.7323"></a>
-<span class="sourceLineNo">7324</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7324"></a>
-<span class="sourceLineNo">7325</span>    return this.replicationScope;<a name="line.7325"></a>
-<span class="sourceLineNo">7326</span>  }<a name="line.7326"></a>
-<span class="sourceLineNo">7327</span><a name="line.7327"></a>
-<span class="sourceLineNo">7328</span>  /**<a name="line.7328"></a>
-<span class="sourceLineNo">7329</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7329"></a>
-<span class="sourceLineNo">7330</span>   * @param other original object<a name="line.7330"></a>
-<span class="sourceLineNo">7331</span>   * @param reporter An interface we can report progress against.<a name="line.7331"></a>
-<span class="sourceLineNo">7332</span>   * @return new HRegion<a name="line.7332"></a>
-<span class="sourceLineNo">7333</span>   */<a name="line.7333"></a>
-<span class="sourceLineNo">7334</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7334"></a>
-<span class="sourceLineNo">7335</span>      throws IOException {<a name="line.7335"></a>
-<span class="sourceLineNo">7336</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7336"></a>
-<span class="sourceLineNo">7337</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7337"></a>
-<span class="sourceLineNo">7338</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7338"></a>
-<span class="sourceLineNo">7339</span>    return r.openHRegion(reporter);<a name="line.7339"></a>
-<span class="sourceLineNo">7340</span>  }<a name="line.7340"></a>
-<span class="sourceLineNo">7341</span><a name="line.7341"></a>
-<span class="sourceLineNo">7342</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7342"></a>
-<span class="sourceLineNo">7343</span>        throws IOException {<a name="line.7343"></a>
-<span class="sourceLineNo">7344</span>    return openHRegion((HRegion)other, reporter);<a name="line.7344"></a>
-<span class="sourceLineNo">7345</span>  }<a name="line.7345"></a>
-<span class="sourceLineNo">7346</span><a name="line.7346"></a>
-<span class="sourceLineNo">7347</span>  /**<a name="line.7347"></a>
-<span class="sourceLineNo">7348</span>   * Open HRegion.<a name="line.7348"></a>
-<span class="sourceLineNo">7349</span>   * Calls initialize and sets sequenceId.<a name="line.7349"></a>
-<span class="sourceLineNo">7350</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7350"></a>
-<span class="sourceLineNo">7351</span>   */<a name="line.7351"></a>
-<span class="sourceLineNo">7352</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7352"></a>
-<span class="sourceLineNo">7353</span>  throws IOException {<a name="line.7353"></a>
-<span class="sourceLineNo">7354</span>    try {<a name="line.7354"></a>
-<span class="sourceLineNo">7355</span>      // Refuse to open the region if we are missing local compression support<a name="line.7355"></a>
-<span class="sourceLineNo">7356</span>      checkCompressionCodecs();<a name="line.7356"></a>
-<span class="sourceLineNo">7357</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7357"></a>
-<span class="sourceLineNo">7358</span>      // codec support is missing<a name="line.7358"></a>
-<span class="sourceLineNo">7359</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7359"></a>
-<span class="sourceLineNo">7360</span>      checkEncryption();<a name="line.7360"></a>
-<span class="sourceLineNo">7361</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7361"></a>
-<span class="sourceLineNo">7362</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
-<span class="sourceLineNo">7363</span>      checkClassLoading();<a name="line.7363"></a>
-<span class="sourceLineNo">7364</span>      this.openSeqNum = initialize(reporter);<a name="line.7364"></a>
-<span class="sourceLineNo">7365</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7365"></a>
-<span class="sourceLineNo">7366</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7366"></a>
-<span class="sourceLineNo">7367</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7367"></a>
-<span class="sourceLineNo">7368</span>      // marker, even if the table is read only.<a name="line.7368"></a>
-<span class="sourceLineNo">7369</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7369"></a>
-<span class="sourceLineNo">7370</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7370"></a>
-<span class="sourceLineNo">7371</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7371"></a>
-<span class="sourceLineNo">7372</span>      }<a name="line.7372"></a>
-<span class="sourceLineNo">7373</span>    } catch(Throwable t) {<a name="line.7373"></a>
-<span class="sourceLineNo">7374</span>      // By coprocessor path wrong region will open failed,<a name="line.7374"></a>
-<span class="sourceLineNo">7375</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7375"></a>
-<span class="sourceLineNo">7376</span>      // add region close when open failed<a name="line.7376"></a>
-<span class="sourceLineNo">7377</span>      this.close();<a name="line.7377"></a>
-<span class="sourceLineNo">7378</span>      throw t;<a name="line.7378"></a>
-<span class="sourceLineNo">7379</span>    }<a name="line.7379"></a>
-<span class="sourceLineNo">7380</span>    return this;<a name="line.7380"></a>
-<span class="sourceLineNo">7381</span>  }<a name="line.7381"></a>
-<span class="sourceLineNo">7382</span><a name="line.7382"></a>
-<span class="sourceLineNo">7383</span>  /**<a name="line.7383"></a>
-<span class="sourceLineNo">7384</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7384"></a>
-<span class="sourceLineNo">7385</span>   * @param conf The Configuration object to use.<a name="line.7385"></a>
-<span class="sourceLineNo">7386</span>   * @param fs Filesystem to use<a name="line.7386"></a>
-<span class="sourceLineNo">7387</span>   * @param info Info for region to be opened.<a name="line.7387"></a>
-<span class="sourceLineNo">7388</span>   * @param htd the table descriptor<a name="line.7388"></a>
-<span class="sourceLineNo">7389</span>   * @return new HRegion<a name="line.7389"></a>
-<span class="sourceLineNo">7390</span>   */<a name="line.7390"></a>
-<span class="sourceLineNo">7391</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7391"></a>
-<span class="sourceLineNo">7392</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7392"></a>
-<span class="sourceLineNo">7393</span>    if (info == null) {<a name="line.7393"></a>
-<span class="sourceLineNo">7394</span>      throw new NullPointerException("Passed region info is null");<a name="line.7394"></a>
-<span class="sourceLineNo">7395</span>    }<a name="line.7395"></a>
-<span class="sourceLineNo">7396</span>    if (LOG.isDebugEnabled()) {<a name="line.7396"></a>
-<span class="sourceLineNo">7397</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7397"></a>
+<span class="sourceLineNo">7250</span>    if (fs == null) {<a name="line.7250"></a>
+<span class="sourceLineNo">7251</span>      fs = rootDir.getFileSystem(conf);<a name="line.7251"></a>
+<span class="sourceLineNo">7252</span>    }<a name="line.7252"></a>
+<span class="sourceLineNo">7253</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, rsServices, reporter);<a name="line.7253"></a>
+<span class="sourceLineNo">7254</span>  }<a name="line.7254"></a>
+<span class="sourceLineNo">7255</span><a name="line.7255"></a>
+<span class="sourceLineNo">7256</span>  /**<a name="line.7256"></a>
+<span class="sourceLineNo">7257</span>   * Open a Region.<a name="line.7257"></a>
+<span class="sourceLineNo">7258</span>   * @param conf The Configuration object to use.<a name="line.7258"></a>
+<span class="sourceLineNo">7259</span>   * @param fs Filesystem to use<a name="line.7259"></a>
+<span class="sourceLineNo">7260</span>   * @param rootDir Root directory for HBase instance<a name="line.7260"></a>
+<span class="sourceLineNo">7261</span>   * @param info Info for region to be opened.<a name="line.7261"></a>
+<span class="sourceLineNo">7262</span>   * @param htd the table descriptor<a name="line.7262"></a>
+<span class="sourceLineNo">7263</span>   * @param wal WAL for region to use. This method will call<a name="line.7263"></a>
+<span class="sourceLineNo">7264</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7264"></a>
+<span class="sourceLineNo">7265</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7265"></a>
+<span class="sourceLineNo">7266</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7266"></a>
+<span class="sourceLineNo">7267</span>   * @return new HRegion<a name="line.7267"></a>
+<span class="sourceLineNo">7268</span>   */<a name="line.7268"></a>
+<span class="sourceLineNo">7269</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7269"></a>
+<span class="sourceLineNo">7270</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal)<a name="line.7270"></a>
+<span class="sourceLineNo">7271</span>      throws IOException {<a name="line.7271"></a>
+<span class="sourceLineNo">7272</span>    return openHRegion(conf, fs, rootDir, info, htd, wal, null, null);<a name="line.7272"></a>
+<span class="sourceLineNo">7273</span>  }<a name="line.7273"></a>
+<span class="sourceLineNo">7274</span><a name="line.7274"></a>
+<span class="sourceLineNo">7275</span>  /**<a name="line.7275"></a>
+<span class="sourceLineNo">7276</span>   * Open a Region.<a name="line.7276"></a>
+<span class="sourceLineNo">7277</span>   * @param conf The Configuration object to use.<a name="line.7277"></a>
+<span class="sourceLineNo">7278</span>   * @param fs Filesystem to use<a name="line.7278"></a>
+<span class="sourceLineNo">7279</span>   * @param rootDir Root directory for HBase instance<a name="line.7279"></a>
+<span class="sourceLineNo">7280</span>   * @param info Info for region to be opened.<a name="line.7280"></a>
+<span class="sourceLineNo">7281</span>   * @param htd the table descriptor<a name="line.7281"></a>
+<span class="sourceLineNo">7282</span>   * @param wal WAL for region to use. This method will call<a name="line.7282"></a>
+<span class="sourceLineNo">7283</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7283"></a>
+<span class="sourceLineNo">7284</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7284"></a>
+<span class="sourceLineNo">7285</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7285"></a>
+<span class="sourceLineNo">7286</span>   * @param rsServices An interface we can request flushes against.<a name="line.7286"></a>
+<span class="sourceLineNo">7287</span>   * @param reporter An interface we can report progress against.<a name="line.7287"></a>
+<span class="sourceLineNo">7288</span>   * @return new HRegion<a name="line.7288"></a>
+<span class="sourceLineNo">7289</span>   */<a name="line.7289"></a>
+<span class="sourceLineNo">7290</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7290"></a>
+<span class="sourceLineNo">7291</span>      final Path rootDir, final RegionInfo info, final TableDescriptor htd, final WAL wal,<a name="line.7291"></a>
+<span class="sourceLineNo">7292</span>      final RegionServerServices rsServices, final CancelableProgressable reporter)<a name="line.7292"></a>
+<span class="sourceLineNo">7293</span>      throws IOException {<a name="line.7293"></a>
+<span class="sourceLineNo">7294</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7294"></a>
+<span class="sourceLineNo">7295</span>    return openHRegion(conf, fs, rootDir, tableDir, info, htd, wal, rsServices, reporter);<a name="line.7295"></a>
+<span class="sourceLineNo">7296</span>  }<a name="line.7296"></a>
+<span class="sourceLineNo">7297</span><a name="line.7297"></a>
+<span class="sourceLineNo">7298</span>  /**<a name="line.7298"></a>
+<span class="sourceLineNo">7299</span>   * Open a Region.<a name="line.7299"></a>
+<span class="sourceLineNo">7300</span>   * @param conf The Configuration object to use.<a name="line.7300"></a>
+<span class="sourceLineNo">7301</span>   * @param fs Filesystem to use<a name="line.7301"></a>
+<span class="sourceLineNo">7302</span>   * @param rootDir Root directory for HBase instance<a name="line.7302"></a>
+<span class="sourceLineNo">7303</span>   * @param info Info for region to be opened.<a name="line.7303"></a>
+<span class="sourceLineNo">7304</span>   * @param htd the table descriptor<a name="line.7304"></a>
+<span class="sourceLineNo">7305</span>   * @param wal WAL for region to use. This method will call<a name="line.7305"></a>
+<span class="sourceLineNo">7306</span>   * WAL#setSequenceNumber(long) passing the result of the call to<a name="line.7306"></a>
+<span class="sourceLineNo">7307</span>   * HRegion#getMinSequenceId() to ensure the wal id is properly kept<a name="line.7307"></a>
+<span class="sourceLineNo">7308</span>   * up.  HRegionStore does this every time it opens a new region.<a name="line.7308"></a>
+<span class="sourceLineNo">7309</span>   * @param rsServices An interface we can request flushes against.<a name="line.7309"></a>
+<span class="sourceLineNo">7310</span>   * @param reporter An interface we can report progress against.<a name="line.7310"></a>
+<span class="sourceLineNo">7311</span>   * @return new HRegion<a name="line.7311"></a>
+<span class="sourceLineNo">7312</span>   */<a name="line.7312"></a>
+<span class="sourceLineNo">7313</span>  public static HRegion openHRegion(final Configuration conf, final FileSystem fs,<a name="line.7313"></a>
+<span class="sourceLineNo">7314</span>      final Path rootDir, final Path tableDir, final RegionInfo info, final TableDescriptor htd,<a name="line.7314"></a>
+<span class="sourceLineNo">7315</span>      final WAL wal, final RegionServerServices rsServices,<a name="line.7315"></a>
+<span class="sourceLineNo">7316</span>      final CancelableProgressable reporter)<a name="line.7316"></a>
+<span class="sourceLineNo">7317</span>      throws IOException {<a name="line.7317"></a>
+<span class="sourceLineNo">7318</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7318"></a>
+<span class="sourceLineNo">7319</span>    if (LOG.isDebugEnabled()) {<a name="line.7319"></a>
+<span class="sourceLineNo">7320</span>      LOG.debug("Opening region: " + info);<a name="line.7320"></a>
+<span class="sourceLineNo">7321</span>    }<a name="line.7321"></a>
+<span class="sourceLineNo">7322</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, rsServices);<a name="line.7322"></a>
+<span class="sourceLineNo">7323</span>    return r.openHRegion(reporter);<a name="line.7323"></a>
+<span class="sourceLineNo">7324</span>  }<a name="line.7324"></a>
+<span class="sourceLineNo">7325</span><a name="line.7325"></a>
+<span class="sourceLineNo">7326</span>  @VisibleForTesting<a name="line.7326"></a>
+<span class="sourceLineNo">7327</span>  public NavigableMap&lt;byte[], Integer&gt; getReplicationScope() {<a name="line.7327"></a>
+<span class="sourceLineNo">7328</span>    return this.replicationScope;<a name="line.7328"></a>
+<span class="sourceLineNo">7329</span>  }<a name="line.7329"></a>
+<span class="sourceLineNo">7330</span><a name="line.7330"></a>
+<span class="sourceLineNo">7331</span>  /**<a name="line.7331"></a>
+<span class="sourceLineNo">7332</span>   * Useful when reopening a closed region (normally for unit tests)<a name="line.7332"></a>
+<span class="sourceLineNo">7333</span>   * @param other original object<a name="line.7333"></a>
+<span class="sourceLineNo">7334</span>   * @param reporter An interface we can report progress against.<a name="line.7334"></a>
+<span class="sourceLineNo">7335</span>   * @return new HRegion<a name="line.7335"></a>
+<span class="sourceLineNo">7336</span>   */<a name="line.7336"></a>
+<span class="sourceLineNo">7337</span>  public static HRegion openHRegion(final HRegion other, final CancelableProgressable reporter)<a name="line.7337"></a>
+<span class="sourceLineNo">7338</span>      throws IOException {<a name="line.7338"></a>
+<span class="sourceLineNo">7339</span>    HRegionFileSystem regionFs = other.getRegionFileSystem();<a name="line.7339"></a>
+<span class="sourceLineNo">7340</span>    HRegion r = newHRegion(regionFs.getTableDir(), other.getWAL(), regionFs.getFileSystem(),<a name="line.7340"></a>
+<span class="sourceLineNo">7341</span>        other.baseConf, other.getRegionInfo(), other.getTableDescriptor(), null);<a name="line.7341"></a>
+<span class="sourceLineNo">7342</span>    return r.openHRegion(reporter);<a name="line.7342"></a>
+<span class="sourceLineNo">7343</span>  }<a name="line.7343"></a>
+<span class="sourceLineNo">7344</span><a name="line.7344"></a>
+<span class="sourceLineNo">7345</span>  public static Region openHRegion(final Region other, final CancelableProgressable reporter)<a name="line.7345"></a>
+<span class="sourceLineNo">7346</span>        throws IOException {<a name="line.7346"></a>
+<span class="sourceLineNo">7347</span>    return openHRegion((HRegion)other, reporter);<a name="line.7347"></a>
+<span class="sourceLineNo">7348</span>  }<a name="line.7348"></a>
+<span class="sourceLineNo">7349</span><a name="line.7349"></a>
+<span class="sourceLineNo">7350</span>  /**<a name="line.7350"></a>
+<span class="sourceLineNo">7351</span>   * Open HRegion.<a name="line.7351"></a>
+<span class="sourceLineNo">7352</span>   * Calls initialize and sets sequenceId.<a name="line.7352"></a>
+<span class="sourceLineNo">7353</span>   * @return Returns &lt;code&gt;this&lt;/code&gt;<a name="line.7353"></a>
+<span class="sourceLineNo">7354</span>   */<a name="line.7354"></a>
+<span class="sourceLineNo">7355</span>  protected HRegion openHRegion(final CancelableProgressable reporter)<a name="line.7355"></a>
+<span class="sourceLineNo">7356</span>  throws IOException {<a name="line.7356"></a>
+<span class="sourceLineNo">7357</span>    try {<a name="line.7357"></a>
+<span class="sourceLineNo">7358</span>      // Refuse to open the region if we are missing local compression support<a name="line.7358"></a>
+<span class="sourceLineNo">7359</span>      checkCompressionCodecs();<a name="line.7359"></a>
+<span class="sourceLineNo">7360</span>      // Refuse to open the region if encryption configuration is incorrect or<a name="line.7360"></a>
+<span class="sourceLineNo">7361</span>      // codec support is missing<a name="line.7361"></a>
+<span class="sourceLineNo">7362</span>      LOG.debug("checking encryption for " + this.getRegionInfo().getEncodedName());<a name="line.7362"></a>
+<span class="sourceLineNo">7363</span>      checkEncryption();<a name="line.7363"></a>
+<span class="sourceLineNo">7364</span>      // Refuse to open the region if a required class cannot be loaded<a name="line.7364"></a>
+<span class="sourceLineNo">7365</span>      LOG.debug("checking classloading for " + this.getRegionInfo().getEncodedName());<a name="line.7365"></a>
+<span class="sourceLineNo">7366</span>      checkClassLoading();<a name="line.7366"></a>
+<span class="sourceLineNo">7367</span>      this.openSeqNum = initialize(reporter);<a name="line.7367"></a>
+<span class="sourceLineNo">7368</span>      this.mvcc.advanceTo(openSeqNum);<a name="line.7368"></a>
+<span class="sourceLineNo">7369</span>      // The openSeqNum must be increased every time when a region is assigned, as we rely on it to<a name="line.7369"></a>
+<span class="sourceLineNo">7370</span>      // determine whether a region has been successfully reopened. So here we always write open<a name="line.7370"></a>
+<span class="sourceLineNo">7371</span>      // marker, even if the table is read only.<a name="line.7371"></a>
+<span class="sourceLineNo">7372</span>      if (wal != null &amp;&amp; getRegionServerServices() != null &amp;&amp;<a name="line.7372"></a>
+<span class="sourceLineNo">7373</span>        RegionReplicaUtil.isDefaultReplica(getRegionInfo())) {<a name="line.7373"></a>
+<span class="sourceLineNo">7374</span>        writeRegionOpenMarker(wal, openSeqNum);<a name="line.7374"></a>
+<span class="sourceLineNo">7375</span>      }<a name="line.7375"></a>
+<span class="sourceLineNo">7376</span>    } catch(Throwable t) {<a name="line.7376"></a>
+<span class="sourceLineNo">7377</span>      // By coprocessor path wrong region will open failed,<a name="line.7377"></a>
+<span class="sourceLineNo">7378</span>      // MetricsRegionWrapperImpl is already init and not close,<a name="line.7378"></a>
+<span class="sourceLineNo">7379</span>      // add region close when open failed<a name="line.7379"></a>
+<span class="sourceLineNo">7380</span>      this.close();<a name="line.7380"></a>
+<span class="sourceLineNo">7381</span>      throw t;<a name="line.7381"></a>
+<span class="sourceLineNo">7382</span>    }<a name="line.7382"></a>
+<span class="sourceLineNo">7383</span>    return this;<a name="line.7383"></a>
+<span class="sourceLineNo">7384</span>  }<a name="line.7384"></a>
+<span class="sourceLineNo">7385</span><a name="line.7385"></a>
+<span class="sourceLineNo">7386</span>  /**<a name="line.7386"></a>
+<span class="sourceLineNo">7387</span>   * Open a Region on a read-only file-system (like hdfs snapshots)<a name="line.7387"></a>
+<span class="sourceLineNo">7388</span>   * @param conf The Configuration object to use.<a name="line.7388"></a>
+<span class="sourceLineNo">7389</span>   * @param fs Filesystem to use<a name="line.7389"></a>
+<span class="sourceLineNo">7390</span>   * @param info Info for region to be opened.<a name="line.7390"></a>
+<span class="sourceLineNo">7391</span>   * @param htd the table descriptor<a name="line.7391"></a>
+<span class="sourceLineNo">7392</span>   * @return new HRegion<a name="line.7392"></a>
+<span class="sourceLineNo">7393</span>   */<a name="line.7393"></a>
+<span class="sourceLineNo">7394</span>  public static HRegion openReadOnlyFileSystemHRegion(final Configuration conf, final FileSystem fs,<a name="line.7394"></a>
+<span class="sourceLineNo">7395</span>      final Path tableDir, RegionInfo info, final TableDescriptor htd) throws IOException {<a name="line.7395"></a>
+<span class="sourceLineNo">7396</span>    if (info == null) {<a name="line.7396"></a>
+<span class="sourceLineNo">7397</span>      throw new NullPointerException("Passed region info is null");<a name="line.7397"></a>
 <span class="sourceLineNo">7398</span>    }<a name="line.7398"></a>
-<span class="sourceLineNo">7399</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7399"></a>
-<span class="sourceLineNo">7400</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7400"></a>
+<span class="sourceLineNo">7399</span>    if (LOG.isDebugEnabled()) {<a name="line.7399"></a>
+<span class="sourceLineNo">7400</span>      LOG.debug("Opening region (readOnly filesystem): " + info);<a name="line.7400"></a>
 <span class="sourceLineNo">7401</span>    }<a name="line.7401"></a>
-<span class="sourceLineNo">7402</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7402"></a>
-<span class="sourceLineNo">7403</span>    r.writestate.setReadOnly(true);<a name="line.7403"></a>
-<span class="sourceLineNo">7404</span>    return r.openHRegion(null);<a name="line.7404"></a>
-<span class="sourceLineNo">7405</span>  }<a name="line.7405"></a>
-<span class="sourceLineNo">7406</span><a name="line.7406"></a>
-<span class="sourceLineNo">7407</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7407"></a>
-<span class="sourceLineNo">7408</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7408"></a>
-<span class="sourceLineNo">7409</span>      final RegionServerServices rsServices,<a name="line.7409"></a>
-<span class="sourceLineNo">7410</span>      final CancelableProgressable reporter)<a name="line.7410"></a>
-<span class="sourceLineNo">7411</span>      throws IOException {<a name="line.7411"></a>
-<span class="sourceLineNo">7412</span><a name="line.7412"></a>
-<span class="sourceLineNo">7413</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7413"></a>
-<span class="sourceLineNo">7414</span><a name="line.7414"></a>
-<span class="sourceLineNo">7415</span>    if (LOG.isDebugEnabled()) {<a name="line.7415"></a>
-<span class="sourceLineNo">7416</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7416"></a>
-<span class="sourceLineNo">7417</span>    }<a name="line.7417"></a>
-<span class="sourceLineNo">7418</span><a name="line.7418"></a>
-<span class="sourceLineNo">7419</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7419"></a>
-<span class="sourceLineNo">7420</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7420"></a>
+<span class="sourceLineNo">7402</span>    if (info.getReplicaId() &lt;= 0) {<a name="line.7402"></a>
+<span class="sourceLineNo">7403</span>      info = RegionInfoBuilder.newBuilder(info).setReplicaId(1).build();<a name="line.7403"></a>
+<span class="sourceLineNo">7404</span>    }<a name="line.7404"></a>
+<span class="sourceLineNo">7405</span>    HRegion r = HRegion.newHRegion(tableDir, null, fs, conf, info, htd, null);<a name="line.7405"></a>
+<span class="sourceLineNo">7406</span>    r.writestate.setReadOnly(true);<a name="line.7406"></a>
+<span class="sourceLineNo">7407</span>    return r.openHRegion(null);<a name="line.7407"></a>
+<span class="sourceLineNo">7408</span>  }<a name="line.7408"></a>
+<span class="sourceLineNo">7409</span><a name="line.7409"></a>
+<span class="sourceLineNo">7410</span>  public static void warmupHRegion(final RegionInfo info,<a name="line.7410"></a>
+<span class="sourceLineNo">7411</span>      final TableDescriptor htd, final WAL wal, final Configuration conf,<a name="line.7411"></a>
+<span class="sourceLineNo">7412</span>      final RegionServerServices rsServices,<a name="line.7412"></a>
+<span class="sourceLineNo">7413</span>      final CancelableProgressable reporter)<a name="line.7413"></a>
+<span class="sourceLineNo">7414</span>      throws IOException {<a name="line.7414"></a>
+<span class="sourceLineNo">7415</span><a name="line.7415"></a>
+<span class="sourceLineNo">7416</span>    if (info == null) throw new NullPointerException("Passed region info is null");<a name="line.7416"></a>
+<span class="sourceLineNo">7417</span><a name="line.7417"></a>
+<span class="sourceLineNo">7418</span>    if (LOG.isDebugEnabled()) {<a name="line.7418"></a>
+<span class="sourceLineNo">7419</span>      LOG.debug("HRegion.Warming up region: " + info);<a name="line.7419"></a>
+<span class="sourceLineNo">7420</span>    }<a name="line.7420"></a>
 <span class="sourceLineNo">7421</span><a name="line.7421"></a>
-<span class="sourceLineNo">7422</span>    FileSystem fs = null;<a name="line.7422"></a>
-<span class="sourceLineNo">7423</span>    if (rsServices != null) {<a name="line.7423"></a>
-<span class="sourceLineNo">7424</span>      fs = rsServices.getFileSystem();<a name="line.7424"></a>
-<span class="sourceLineNo">7425</span>    }<a name="line.7425"></a>
-<span class="sourceLineNo">7426</span>    if (fs == null) {<a name="line.7426"></a>
-<span class="sourceLineNo">7427</span>      fs = rootDir.getFileSystem(conf);<a name="line.7427"></a>
+<span class="sourceLineNo">7422</span>    Path rootDir = FSUtils.getRootDir(conf);<a name="line.7422"></a>
+<span class="sourceLineNo">7423</span>    Path tableDir = FSUtils.getTableDir(rootDir, info.getTable());<a name="line.7423"></a>
+<span class="sourceLineNo">7424</span><a name="line.7424"></a>
+<span class="sourceLineNo">7425</span>    FileSystem fs = null;<a name="line.7425"></a>
+<span class="sourceLineNo">7426</span>    if (rsServices != null) {<a name="line.7426"></a>
+<span class="sourceLineNo">7427</span>      fs = rsServices.getFileSystem();<a name="line.7427"></a>
 <span class="sourceLineNo">7428</span>    }<a name="line.7428"></a>
-<span class="sourceLineNo">7429</span><a name="line.7429"></a>
-<span class="sourceLineNo">7430</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7430"></a>
-<span class="sourceLineNo">7431</span>    r.initializeWarmup(reporter);<a name="line.7431"></a>
-<span class="sourceLineNo">7432</span>  }<a name="line.7432"></a>
-<span class="sourceLineNo">7433</span><a name="line.7433"></a>
-<span class="sourceLineNo">7434</span><a name="line.7434"></a>
-<span class="sourceLineNo">7435</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7435"></a>
-<span class="sourceLineNo">7436</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7436"></a>
-<span class="sourceLineNo">7437</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7437"></a>
-<span class="sourceLineNo">7438</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7438"></a>
-<span class="sourceLineNo">7439</span>    }<a name="line.7439"></a>
-<span class="sourceLineNo">7440</span>  }<a name="line.7440"></a>
-<span class="sourceLineNo">7441</span><a name="line.7441"></a>
-<span class="sourceLineNo">7442</span>  private void checkEncryption() throws IOException {<a name="line.7442"></a>
-<span class="sourceLineNo">7443</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7443"></a>
-<span class="sourceLineNo">7444</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7444"></a>
-<span class="sourceLineNo">7445</span>    }<a name="line.7445"></a>
-<span class="sourceLineNo">7446</span>  }<a name="line.7446"></a>
-<span class="sourceLineNo">7447</span><a name="line.7447"></a>
-<span class="sourceLineNo">7448</span>  private void checkClassLoading() throws IOException {<a name="line.7448"></a>
-<span class="sourceLineNo">7449</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7449"></a>
-<span class="sourceLineNo">7450</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7450"></a>
-<span class="sourceLineNo">7451</span>  }<a name="line.7451"></a>
-<span class="sourceLineNo">7452</span><a name="line.7452"></a>
-<span class="sourceLineNo">7453</span>  /**<a name="line.7453"></a>
-<span class="sourceLineNo">7454</span>   * Computes the Path of the HRegion<a name="line.7454"></a>
-<span class="sourceLineNo">7455</span>   *<a name="line.7455"></a>
-<span class="sourceLineNo">7456</span>   * @param tabledir qualified path for table<a name="line.7456"></a>
-<span class="sourceLineNo">7457</span>   * @param name ENCODED region name<a name="line.7457"></a>
-<span class="sourceLineNo">7458</span>   * @return Path of HRegion directory<a name="line.7458"></a>
-<span class="sourceLineNo">7459</span>   * @deprecated For tests only; to be removed.<a name="line.7459"></a>
-<span class="sourceLineNo">7460</span>   */<a name="line.7460"></a>
-<span class="sourceLineNo">7461</span>  @Deprecated<a name="line.7461"></a>
-<span class="sourceLineNo">7462</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7462"></a>
-<span class="sourceLineNo">7463</span>    return new Path(tabledir, name);<a name="line.7463"></a>
-<span class="sourceLineNo">7464</span>  }<a name="line.7464"></a>
-<span class="sourceLineNo">7465</span><a name="line.7465"></a>
-<span class="sourceLineNo">7466</span>  /**<a name="line.7466"></a>
-<span class="sourceLineNo">7467</span>   * Determines if the specified row is within the row range specified by the<a name="line.7467"></a>
-<span class="sourceLineNo">7468</span>   * specified RegionInfo<a name="line.7468"></a>
-<span class="sourceLineNo">7469</span>   *<a name="line.7469"></a>
-<span class="sourceLineNo">7470</span>   * @param info RegionInfo that specifies the row range<a name="line.7470"></a>
-<span class="sourceLineNo">7471</span>   * @param row row to be checked<a name="line.7471"></a>
-<span class="sourceLineNo">7472</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7472"></a>
-<span class="sourceLineNo">7473</span>   */<a name="line.7473"></a>
-<span class="sourceLineNo">7474</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7474"></a>
-<span class="sourceLineNo">7475</span>    return ((info.getStartKey().length == 0) ||<a name="line.7475"></a>
-<span class="sourceLineNo">7476</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7476"></a>
-<span class="sourceLineNo">7477</span>        ((info.getEndKey().length == 0) ||<a name="line.7477"></a>
-<span class="sourceLineNo">7478</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7478"></a>
-<span class="sourceLineNo">7479</span>  }<a name="line.7479"></a>
-<span class="sourceLineNo">7480</span><a name="line.7480"></a>
-<span class="sourceLineNo">7481</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7481"></a>
-<span class="sourceLineNo">7482</span>      final short length) {<a name="line.7482"></a>
-<span class="sourceLineNo">7483</span>    return ((info.getStartKey().length == 0) ||<a name="line.7483"></a>
-<span class="sourceLineNo">7484</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7484"></a>
-<span class="sourceLineNo">7485</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7485"></a>
-<span class="sourceLineNo">7486</span>        ((info.getEndKey().length == 0) ||<a name="line.7486"></a>
-<span class="sourceLineNo">7487</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7487"></a>
-<span class="sourceLineNo">7488</span>  }<a name="line.7488"></a>
-<span class="sourceLineNo">7489</span><a name="line.7489"></a>
-<span class="sourceLineNo">7490</span>  @Override<a name="line.7490"></a>
-<span class="sourceLineNo">7491</span>  public Result get(final Get get) throws IOException {<a name="line.7491"></a>
-<span class="sourceLineNo">7492</span>    prepareGet(get);<a name="line.7492"></a>
-<span class="sourceLineNo">7493</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7493"></a>
-<span class="sourceLineNo">7494</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7494"></a>
-<span class="sourceLineNo">7495</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7495"></a>
-<span class="sourceLineNo">7496</span>  }<a name="line.7496"></a>
-<span class="sourceLineNo">7497</span><a name="line.7497"></a>
-<span class="sourceLineNo">7498</span>  void prepareGet(final Get get) throws IOException {<a name="line.7498"></a>
-<span class="sourceLineNo">7499</span>    checkRow(get.getRow(), "Get");<a name="line.7499"></a>
-<span class="sourceLineNo">7500</span>    // Verify families are all valid<a name="line.7500"></a>
-<span class="sourceLineNo">7501</span>    if (get.hasFamilies()) {<a name="line.7501"></a>
-<span class="sourceLineNo">7502</span>      for (byte[] family : get.familySet()) {<a name="line.7502"></a>
-<span class="sourceLineNo">7503</span>        checkFamily(family);<a name="line.7503"></a>
-<span class="sourceLineNo">7504</span>      }<a name="line.7504"></a>
-<span class="sourceLineNo">7505</span>    } else { // Adding all families to scanner<a name="line.7505"></a>
-<span class="sourceLineNo">7506</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7506"></a>
-<span class="sourceLineNo">7507</span>        get.addFamily(family);<a name="line.7507"></a>
-<span class="sourceLineNo">7508</span>      }<a name="line.7508"></a>
-<span class="sourceLineNo">7509</span>    }<a name="line.7509"></a>
-<span class="sourceLineNo">7510</span>  }<a name="line.7510"></a>
-<span class="sourceLineNo">7511</span><a name="line.7511"></a>
-<span class="sourceLineNo">7512</span>  @Override<a name="line.7512"></a>
-<span class="sourceLineNo">7513</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7513"></a>
-<span class="sourceLineNo">7514</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7514"></a>
-<span class="sourceLineNo">7515</span>  }<a name="line.7515"></a>
-<span class="sourceLineNo">7516</span><a name="line.7516"></a>
-<span class="sourceLineNo">7517</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7517"></a>
-<span class="sourceLineNo">7518</span>      throws IOException {<a name="line.7518"></a>
-<span class="sourceLineNo">7519</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7519"></a>
-<span class="sourceLineNo">7520</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7520"></a>
-<span class="sourceLineNo">7521</span><a name="line.7521"></a>
-<span class="sourceLineNo">7522</span>    // pre-get CP hook<a name="line.7522"></a>
-<span class="sourceLineNo">7523</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7523"></a>
-<span class="sourceLineNo">7524</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7524"></a>
-<span class="sourceLineNo">7525</span>        metricsUpdateForGet(results, before);<a name="line.7525"></a>
-<span class="sourceLineNo">7526</span>        return results;<a name="line.7526"></a>
-<span class="sourceLineNo">7527</span>      }<a name="line.7527"></a>
-<span class="sourceLineNo">7528</span>    }<a name="line.7528"></a>
-<span class="sourceLineNo">7529</span>    Scan scan = new Scan(get);<a name="line.7529"></a>
-<span class="sourceLineNo">7530</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7530"></a>
-<span class="sourceLineNo">7531</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7531"></a>
-<span class="sourceLineNo">7532</span>    }<a name="line.7532"></a>
-<span class="sourceLineNo">7533</span>    RegionScanner scanner = null;<a name="line.7533"></a>
-<span class="sourceLineNo">7534</span>    try {<a name="line.7534"></a>
-<span class="sourceLineNo">7535</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7535"></a>
-<span class="sourceLineNo">7536</span>      scanner.next(results);<a name="line.7536"></a>
-<span class="sourceLineNo">7537</span>    } finally {<a name="line.7537"></a>
-<span class="sourceLineNo">7538</span>      if (scanner != null)<a name="line.7538"></a>
-<span class="sourceLineNo">7539</span>        scanner.close();<a name="line.7539"></a>
-<span class="sourceLineNo">7540</span>    }<a name="line.7540"></a>
-<span class="sourceLineNo">7541</span><a name="line.7541"></a>
-<span class="sourceLineNo">7542</span>    // post-get CP hook<a name="line.7542"></a>
-<span class="sourceLineNo">7543</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7543"></a>
-<span class="sourceLineNo">7544</span>      coprocessorHost.postGet(get, results);<a name="line.7544"></a>
-<span class="sourceLineNo">7545</span>    }<a name="line.7545"></a>
-<span class="sourceLineNo">7546</span><a name="line.7546"></a>
-<span class="sourceLineNo">7547</span>    metricsUpdateForGet(results, before);<a name="line.7547"></a>
-<span class="sourceLineNo">7548</span><a name="line.7548"></a>
-<span class="sourceLineNo">7549</span>    return results;<a name="line.7549"></a>
-<span class="sourceLineNo">7550</span>  }<a name="line.7550"></a>
+<span class="sourceLineNo">7429</span>    if (fs == null) {<a name="line.7429"></a>
+<span class="sourceLineNo">7430</span>      fs = rootDir.getFileSystem(conf);<a name="line.7430"></a>
+<span class="sourceLineNo">7431</span>    }<a name="line.7431"></a>
+<span class="sourceLineNo">7432</span><a name="line.7432"></a>
+<span class="sourceLineNo">7433</span>    HRegion r = HRegion.newHRegion(tableDir, wal, fs, conf, info, htd, null);<a name="line.7433"></a>
+<span class="sourceLineNo">7434</span>    r.initializeWarmup(reporter);<a name="line.7434"></a>
+<span class="sourceLineNo">7435</span>  }<a name="line.7435"></a>
+<span class="sourceLineNo">7436</span><a name="line.7436"></a>
+<span class="sourceLineNo">7437</span><a name="line.7437"></a>
+<span class="sourceLineNo">7438</span>  private void checkCompressionCodecs() throws IOException {<a name="line.7438"></a>
+<span class="sourceLineNo">7439</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7439"></a>
+<span class="sourceLineNo">7440</span>      CompressionTest.testCompression(fam.getCompressionType());<a name="line.7440"></a>
+<span class="sourceLineNo">7441</span>      CompressionTest.testCompression(fam.getCompactionCompressionType());<a name="line.7441"></a>
+<span class="sourceLineNo">7442</span>    }<a name="line.7442"></a>
+<span class="sourceLineNo">7443</span>  }<a name="line.7443"></a>
+<span class="sourceLineNo">7444</span><a name="line.7444"></a>
+<span class="sourceLineNo">7445</span>  private void checkEncryption() throws IOException {<a name="line.7445"></a>
+<span class="sourceLineNo">7446</span>    for (ColumnFamilyDescriptor fam: this.htableDescriptor.getColumnFamilies()) {<a name="line.7446"></a>
+<span class="sourceLineNo">7447</span>      EncryptionTest.testEncryption(conf, fam.getEncryptionType(), fam.getEncryptionKey());<a name="line.7447"></a>
+<span class="sourceLineNo">7448</span>    }<a name="line.7448"></a>
+<span class="sourceLineNo">7449</span>  }<a name="line.7449"></a>
+<span class="sourceLineNo">7450</span><a name="line.7450"></a>
+<span class="sourceLineNo">7451</span>  private void checkClassLoading() throws IOException {<a name="line.7451"></a>
+<span class="sourceLineNo">7452</span>    RegionSplitPolicy.getSplitPolicyClass(this.htableDescriptor, conf);<a name="line.7452"></a>
+<span class="sourceLineNo">7453</span>    RegionCoprocessorHost.testTableCoprocessorAttrs(conf, this.htableDescriptor);<a name="line.7453"></a>
+<span class="sourceLineNo">7454</span>  }<a name="line.7454"></a>
+<span class="sourceLineNo">7455</span><a name="line.7455"></a>
+<span class="sourceLineNo">7456</span>  /**<a name="line.7456"></a>
+<span class="sourceLineNo">7457</span>   * Computes the Path of the HRegion<a name="line.7457"></a>
+<span class="sourceLineNo">7458</span>   *<a name="line.7458"></a>
+<span class="sourceLineNo">7459</span>   * @param tabledir qualified path for table<a name="line.7459"></a>
+<span class="sourceLineNo">7460</span>   * @param name ENCODED region name<a name="line.7460"></a>
+<span class="sourceLineNo">7461</span>   * @return Path of HRegion directory<a name="line.7461"></a>
+<span class="sourceLineNo">7462</span>   * @deprecated For tests only; to be removed.<a name="line.7462"></a>
+<span class="sourceLineNo">7463</span>   */<a name="line.7463"></a>
+<span class="sourceLineNo">7464</span>  @Deprecated<a name="line.7464"></a>
+<span class="sourceLineNo">7465</span>  public static Path getRegionDir(final Path tabledir, final String name) {<a name="line.7465"></a>
+<span class="sourceLineNo">7466</span>    return new Path(tabledir, name);<a name="line.7466"></a>
+<span class="sourceLineNo">7467</span>  }<a name="line.7467"></a>
+<span class="sourceLineNo">7468</span><a name="line.7468"></a>
+<span class="sourceLineNo">7469</span>  /**<a name="line.7469"></a>
+<span class="sourceLineNo">7470</span>   * Determines if the specified row is within the row range specified by the<a name="line.7470"></a>
+<span class="sourceLineNo">7471</span>   * specified RegionInfo<a name="line.7471"></a>
+<span class="sourceLineNo">7472</span>   *<a name="line.7472"></a>
+<span class="sourceLineNo">7473</span>   * @param info RegionInfo that specifies the row range<a name="line.7473"></a>
+<span class="sourceLineNo">7474</span>   * @param row row to be checked<a name="line.7474"></a>
+<span class="sourceLineNo">7475</span>   * @return true if the row is within the range specified by the RegionInfo<a name="line.7475"></a>
+<span class="sourceLineNo">7476</span>   */<a name="line.7476"></a>
+<span class="sourceLineNo">7477</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row) {<a name="line.7477"></a>
+<span class="sourceLineNo">7478</span>    return ((info.getStartKey().length == 0) ||<a name="line.7478"></a>
+<span class="sourceLineNo">7479</span>        (Bytes.compareTo(info.getStartKey(), row) &lt;= 0)) &amp;&amp;<a name="line.7479"></a>
+<span class="sourceLineNo">7480</span>        ((info.getEndKey().length == 0) ||<a name="line.7480"></a>
+<span class="sourceLineNo">7481</span>            (Bytes.compareTo(info.getEndKey(), row) &gt; 0));<a name="line.7481"></a>
+<span class="sourceLineNo">7482</span>  }<a name="line.7482"></a>
+<span class="sourceLineNo">7483</span><a name="line.7483"></a>
+<span class="sourceLineNo">7484</span>  public static boolean rowIsInRange(RegionInfo info, final byte [] row, final int offset,<a name="line.7484"></a>
+<span class="sourceLineNo">7485</span>      final short length) {<a name="line.7485"></a>
+<span class="sourceLineNo">7486</span>    return ((info.getStartKey().length == 0) ||<a name="line.7486"></a>
+<span class="sourceLineNo">7487</span>        (Bytes.compareTo(info.getStartKey(), 0, info.getStartKey().length,<a name="line.7487"></a>
+<span class="sourceLineNo">7488</span>          row, offset, length) &lt;= 0)) &amp;&amp;<a name="line.7488"></a>
+<span class="sourceLineNo">7489</span>        ((info.getEndKey().length == 0) ||<a name="line.7489"></a>
+<span class="sourceLineNo">7490</span>          (Bytes.compareTo(info.getEndKey(), 0, info.getEndKey().length, row, offset, length) &gt; 0));<a name="line.7490"></a>
+<span class="sourceLineNo">7491</span>  }<a name="line.7491"></a>
+<span class="sourceLineNo">7492</span><a name="line.7492"></a>
+<span class="sourceLineNo">7493</span>  @Override<a name="line.7493"></a>
+<span class="sourceLineNo">7494</span>  public Result get(final Get get) throws IOException {<a name="line.7494"></a>
+<span class="sourceLineNo">7495</span>    prepareGet(get);<a name="line.7495"></a>
+<span class="sourceLineNo">7496</span>    List&lt;Cell&gt; results = get(get, true);<a name="line.7496"></a>
+<span class="sourceLineNo">7497</span>    boolean stale = this.getRegionInfo().getReplicaId() != 0;<a name="line.7497"></a>
+<span class="sourceLineNo">7498</span>    return Result.create(results, get.isCheckExistenceOnly() ? !results.isEmpty() : null, stale);<a name="line.7498"></a>
+<span class="sourceLineNo">7499</span>  }<a name="line.7499"></a>
+<span class="sourceLineNo">7500</span><a name="line.7500"></a>
+<span class="sourceLineNo">7501</span>  void prepareGet(final Get get) throws IOException {<a name="line.7501"></a>
+<span class="sourceLineNo">7502</span>    checkRow(get.getRow(), "Get");<a name="line.7502"></a>
+<span class="sourceLineNo">7503</span>    // Verify families are all valid<a name="line.7503"></a>
+<span class="sourceLineNo">7504</span>    if (get.hasFamilies()) {<a name="line.7504"></a>
+<span class="sourceLineNo">7505</span>      for (byte[] family : get.familySet()) {<a name="line.7505"></a>
+<span class="sourceLineNo">7506</span>        checkFamily(family);<a name="line.7506"></a>
+<span class="sourceLineNo">7507</span>      }<a name="line.7507"></a>
+<span class="sourceLineNo">7508</span>    } else { // Adding all families to scanner<a name="line.7508"></a>
+<span class="sourceLineNo">7509</span>      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {<a name="line.7509"></a>
+<span class="sourceLineNo">7510</span>        get.addFamily(family);<a name="line.7510"></a>
+<span class="sourceLineNo">7511</span>      }<a name="line.7511"></a>
+<span class="sourceLineNo">7512</span>    }<a name="line.7512"></a>
+<span class="sourceLineNo">7513</span>  }<a name="line.7513"></a>
+<span class="sourceLineNo">7514</span><a name="line.7514"></a>
+<span class="sourceLineNo">7515</span>  @Override<a name="line.7515"></a>
+<span class="sourceLineNo">7516</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor) throws IOException {<a name="line.7516"></a>
+<span class="sourceLineNo">7517</span>    return get(get, withCoprocessor, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7517"></a>
+<span class="sourceLineNo">7518</span>  }<a name="line.7518"></a>
+<span class="sourceLineNo">7519</span><a name="line.7519"></a>
+<span class="sourceLineNo">7520</span>  public List&lt;Cell&gt; get(Get get, boolean withCoprocessor, long nonceGroup, long nonce)<a name="line.7520"></a>
+<span class="sourceLineNo">7521</span>      throws IOException {<a name="line.7521"></a>
+<span class="sourceLineNo">7522</span>    List&lt;Cell&gt; results = new ArrayList&lt;&gt;();<a name="line.7522"></a>
+<span class="sourceLineNo">7523</span>    long before =  EnvironmentEdgeManager.currentTime();<a name="line.7523"></a>
+<span class="sourceLineNo">7524</span><a name="line.7524"></a>
+<span class="sourceLineNo">7525</span>    // pre-get CP hook<a name="line.7525"></a>
+<span class="sourceLineNo">7526</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7526"></a>
+<span class="sourceLineNo">7527</span>      if (coprocessorHost.preGet(get, results)) {<a name="line.7527"></a>
+<span class="sourceLineNo">7528</span>        metricsUpdateForGet(results, before);<a name="line.7528"></a>
+<span class="sourceLineNo">7529</span>        return results;<a name="line.7529"></a>
+<span class="sourceLineNo">7530</span>      }<a name="line.7530"></a>
+<span class="sourceLineNo">7531</span>    }<a name="line.7531"></a>
+<span class="sourceLineNo">7532</span>    Scan scan = new Scan(get);<a name="line.7532"></a>
+<span class="sourceLineNo">7533</span>    if (scan.getLoadColumnFamiliesOnDemandValue() == null) {<a name="line.7533"></a>
+<span class="sourceLineNo">7534</span>      scan.setLoadColumnFamiliesOnDemand(isLoadingCfsOnDemandDefault());<a name="line.7534"></a>
+<span class="sourceLineNo">7535</span>    }<a name="line.7535"></a>
+<span class="sourceLineNo">7536</span>    RegionScanner scanner = null;<a name="line.7536"></a>
+<span class="sourceLineNo">7537</span>    try {<a name="line.7537"></a>
+<span class="sourceLineNo">7538</span>      scanner = getScanner(scan, null, nonceGroup, nonce);<a name="line.7538"></a>
+<span class="sourceLineNo">7539</span>      scanner.next(results);<a name="line.7539"></a>
+<span class="sourceLineNo">7540</span>    } finally {<a name="line.7540"></a>
+<span class="sourceLineNo">7541</span>      if (scanner != null)<a name="line.7541"></a>
+<span class="sourceLineNo">7542</span>        scanner.close();<a name="line.7542"></a>
+<span class="sourceLineNo">7543</span>    }<a name="line.7543"></a>
+<span class="sourceLineNo">7544</span><a name="line.7544"></a>
+<span class="sourceLineNo">7545</span>    // post-get CP hook<a name="line.7545"></a>
+<span class="sourceLineNo">7546</span>    if (withCoprocessor &amp;&amp; (coprocessorHost != null)) {<a name="line.7546"></a>
+<span class="sourceLineNo">7547</span>      coprocessorHost.postGet(get, results);<a name="line.7547"></a>
+<span class="sourceLineNo">7548</span>    }<a name="line.7548"></a>
+<span class="sourceLineNo">7549</span><a name="line.7549"></a>
+<span class="sourceLineNo">7550</span>    metricsUpdateForGet(results, before);<a name="line.7550"></a>
 <span class="sourceLineNo">7551</span><a name="line.7551"></a>
-<span class="sourceLineNo">7552</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7552"></a>
-<span class="sourceLineNo">7553</span>    if (this.metricsRegion != null) {<a name="line.7553"></a>
-<span class="sourceLineNo">7554</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7554"></a>
-<span class="sourceLineNo">7555</span>    }<a name="line.7555"></a>
-<span class="sourceLineNo">7556</span>  }<a name="line.7556"></a>
-<span class="sourceLineNo">7557</span><a name="line.7557"></a>
-<span class="sourceLineNo">7558</span>  @Override<a name="line.7558"></a>
-<span class="sourceLineNo">7559</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7559"></a>
-<span class="sourceLineNo">7560</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7560"></a>
-<span class="sourceLineNo">7561</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7561"></a>
-<span class="sourceLineNo">7562</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7562"></a>
-<span class="sourceLineNo">7563</span>        HConstants.NO_NONCE);<a name="line.7563"></a>
-<span class="sourceLineNo">7564</span>  }<a name="line.7564"></a>
-<span class="sourceLineNo">7565</span><a name="line.7565"></a>
-<span class="sourceLineNo">7566</span>  /**<a name="line.7566"></a>
-<span class="sourceLineNo">7567</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7567"></a>
-<span class="sourceLineNo">7568</span>   * @param mutations The list of mutations to perform.<a name="line.7568"></a>
-<span class="sourceLineNo">7569</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7569"></a>
-<span class="sourceLineNo">7570</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7570"></a>
-<span class="sourceLineNo">7571</span>   * @param rowsToLock Rows to lock<a name="line.7571"></a>
-<span class="sourceLineNo">7572</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7572"></a>
-<span class="sourceLineNo">7573</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7573"></a>
-<span class="sourceLineNo">7574</span>   * If multiple rows are locked care should be taken that<a name="line.7574"></a>
-<span class="sourceLineNo">7575</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7575"></a>
-<span class="sourceLineNo">7576</span>   * @throws IOException<a name="line.7576"></a>
-<span class="sourceLineNo">7577</span>   */<a name="line.7577"></a>
-<span class="sourceLineNo">7578</span>  @Override<a name="line.7578"></a>
-<span class="sourceLineNo">7579</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7579"></a>
-<span class="sourceLineNo">7580</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7580"></a>
-<span class="sourceLineNo">7581</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7581"></a>
-<span class="sourceLineNo">7582</span>        true, nonceGroup, nonce) {<a name="line.7582"></a>
-<span class="sourceLineNo">7583</span>      @Override<a name="line.7583"></a>
-<span class="sourceLineNo">7584</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7584"></a>
-<span class="sourceLineNo">7585</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7585"></a>
-<span class="sourceLineNo">7586</span>        RowLock prevRowLock = null;<a name="line.7586"></a>
-<span class="sourceLineNo">7587</span>        for (byte[] row : rowsToLock) {<a name="line.7587"></a>
-<span class="sourceLineNo">7588</span>          try {<a name="line.7588"></a>
-<span class="sourceLineNo">7589</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7589"></a>
-<span class="sourceLineNo">7590</span>            if (rowLock != prevRowLock) {<a name="line.7590"></a>
-<span class="sourceLineNo">7591</span>              acquiredRowLocks.add(rowLock);<a name="line.7591"></a>
-<span class="sourceLineNo">7592</span>              prevRowLock = rowLock;<a name="line.7592"></a>
-<span class="sourceLineNo">7593</span>            }<a name="line.7593"></a>
-<span class="sourceLineNo">7594</span>          } catch (IOException ioe) {<a name="line.7594"></a>
-<span class="sourceLineNo">7595</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7595"></a>
-<span class="sourceLineNo">7596</span>            throw ioe;<a name="line.7596"></a>
-<span class="sourceLineNo">7597</span>          }<a name="line.7597"></a>
-<span class="sourceLineNo">7598</span>        }<a name="line.7598"></a>
-<span class="sourceLineNo">7599</span>        return createMiniBatch(size(), size());<a name="line.7599"></a>
-<span class="sourceLineNo">7600</span>      }<a name="line.7600"></a>
-<span class="sourceLineNo">7601</span>    });<a name="line.7601"></a>
-<span class="sourceLineNo">7602</span>  }<a name="line.7602"></a>
-<span class="sourceLineNo">7603</span><a name="line.7603"></a>
-<span class="sourceLineNo">7604</span>  /**<a name="line.7604"></a>
-<span class="sourceLineNo">7605</span>   * @return statistics about the current load of the region<a name="line.7605"></a>
-<span class="sourceLineNo">7606</span>   */<a name="line.7606"></a>
-<span class="sourceLineNo">7607</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7607"></a>
-<span class="sourceLineNo">7608</span>    if (!regionStatsEnabled) {<a name="line.7608"></a>
-<span class="sourceLineNo">7609</span>      return null;<a name="line.7609"></a>
-<span class="sourceLineNo">7610</span>    }<a name="line.7610"></a>
-<span class="sourceLineNo">7611</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7611"></a>
-<span class="sourceLineNo">7612</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7612"></a>
-<span class="sourceLineNo">7613</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7613"></a>
-<span class="sourceLineNo">7614</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7614"></a>
-<span class="sourceLineNo">7615</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7615"></a>
-<span class="sourceLineNo">7616</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7616"></a>
-<span class="sourceLineNo">7617</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7617"></a>
-<span class="sourceLineNo">7618</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7618"></a>
-<span class="sourceLineNo">7619</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7619"></a>
-<span class="sourceLineNo">7620</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7620"></a>
-<span class="sourceLineNo">7621</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7621"></a>
-<span class="sourceLineNo">7622</span>      }<a name="line.7622"></a>
-<span class="sourceLineNo">7623</span>    }<a name="line.7623"></a>
-<span class="sourceLineNo">7624</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7624"></a>
-<span class="sourceLineNo">7625</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7625"></a>
-<span class="sourceLineNo">7626</span>    return stats.build();<a name="line.7626"></a>
-<span class="sourceLineNo">7627</span>  }<a name="line.7627"></a>
-<span class="sourceLineNo">7628</span><a name="line.7628"></a>
-<span class="sourceLineNo">7629</span>  @Override<a name="line.7629"></a>
-<span class="sourceLineNo">7630</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7630"></a>
-<span class="sourceLineNo">7631</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7631"></a>
-<span class="sourceLineNo">7632</span>  }<a name="line.7632"></a>
-<span class="sourceLineNo">7633</span><a name="line.7633"></a>
-<span class="sourceLineNo">7634</span>  @Override<a name="line.7634"></a>
-<span class="sourceLineNo">7635</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7635"></a>
-<span class="sourceLineNo">7636</span>      throws IOException {<a name="line.7636"></a>
-<span class="sourceLineNo">7637</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7637"></a>
-<span class="sourceLineNo">7638</span>  }<a name="line.7638"></a>
-<span class="sourceLineNo">7639</span><a name="line.7639"></a>
-<span class="sourceLineNo">7640</span>  @Override<a name="line.7640"></a>
-<span class="sourceLineNo">7641</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7641"></a>
-<span class="sourceLineNo">7642</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7642"></a>
-<span class="sourceLineNo">7643</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7643"></a>
-<span class="sourceLineNo">7644</span>      checkRow(row, "processRowsWithLocks");<a name="line.7644"></a>
-<span class="sourceLineNo">7645</span>    }<a name="line.7645"></a>
-<span class="sourceLineNo">7646</span>    if (!processor.readOnly()) {<a name="line.7646"></a>
-<span class="sourceLineNo">7647</span>      checkReadOnly();<a name="line.7647"></a>
+<span class="sourceLineNo">7552</span>    return results;<a name="line.7552"></a>
+<span class="sourceLineNo">7553</span>  }<a name="line.7553"></a>
+<span class="sourceLineNo">7554</span><a name="line.7554"></a>
+<span class="sourceLineNo">7555</span>  void metricsUpdateForGet(List&lt;Cell&gt; results, long before) {<a name="line.7555"></a>
+<span class="sourceLineNo">7556</span>    if (this.metricsRegion != null) {<a name="line.7556"></a>
+<span class="sourceLineNo">7557</span>      this.metricsRegion.updateGet(EnvironmentEdgeManager.currentTime() - before);<a name="line.7557"></a>
+<span class="sourceLineNo">7558</span>    }<a name="line.7558"></a>
+<span class="sourceLineNo">7559</span>  }<a name="line.7559"></a>
+<span class="sourceLineNo">7560</span><a name="line.7560"></a>
+<span class="sourceLineNo">7561</span>  @Override<a name="line.7561"></a>
+<span class="sourceLineNo">7562</span>  public void mutateRow(RowMutations rm) throws IOException {<a name="line.7562"></a>
+<span class="sourceLineNo">7563</span>    // Don't need nonces here - RowMutations only supports puts and deletes<a name="line.7563"></a>
+<span class="sourceLineNo">7564</span>    final List&lt;Mutation&gt; m = rm.getMutations();<a name="line.7564"></a>
+<span class="sourceLineNo">7565</span>    batchMutate(m.toArray(new Mutation[m.size()]), true, HConstants.NO_NONCE,<a name="line.7565"></a>
+<span class="sourceLineNo">7566</span>        HConstants.NO_NONCE);<a name="line.7566"></a>
+<span class="sourceLineNo">7567</span>  }<a name="line.7567"></a>
+<span class="sourceLineNo">7568</span><a name="line.7568"></a>
+<span class="sourceLineNo">7569</span>  /**<a name="line.7569"></a>
+<span class="sourceLineNo">7570</span>   * Perform atomic (all or none) mutations within the region.<a name="line.7570"></a>
+<span class="sourceLineNo">7571</span>   * @param mutations The list of mutations to perform.<a name="line.7571"></a>
+<span class="sourceLineNo">7572</span>   * &lt;code&gt;mutations&lt;/code&gt; can contain operations for multiple rows.<a name="line.7572"></a>
+<span class="sourceLineNo">7573</span>   * Caller has to ensure that all rows are contained in this region.<a name="line.7573"></a>
+<span class="sourceLineNo">7574</span>   * @param rowsToLock Rows to lock<a name="line.7574"></a>
+<span class="sourceLineNo">7575</span>   * @param nonceGroup Optional nonce group of the operation (client Id)<a name="line.7575"></a>
+<span class="sourceLineNo">7576</span>   * @param nonce Optional nonce of the operation (unique random id to ensure "more idempotence")<a name="line.7576"></a>
+<span class="sourceLineNo">7577</span>   * If multiple rows are locked care should be taken that<a name="line.7577"></a>
+<span class="sourceLineNo">7578</span>   * &lt;code&gt;rowsToLock&lt;/code&gt; is sorted in order to avoid deadlocks.<a name="line.7578"></a>
+<span class="sourceLineNo">7579</span>   * @throws IOException<a name="line.7579"></a>
+<span class="sourceLineNo">7580</span>   */<a name="line.7580"></a>
+<span class="sourceLineNo">7581</span>  @Override<a name="line.7581"></a>
+<span class="sourceLineNo">7582</span>  public void mutateRowsWithLocks(Collection&lt;Mutation&gt; mutations,<a name="line.7582"></a>
+<span class="sourceLineNo">7583</span>      Collection&lt;byte[]&gt; rowsToLock, long nonceGroup, long nonce) throws IOException {<a name="line.7583"></a>
+<span class="sourceLineNo">7584</span>    batchMutate(new MutationBatchOperation(this, mutations.toArray(new Mutation[mutations.size()]),<a name="line.7584"></a>
+<span class="sourceLineNo">7585</span>        true, nonceGroup, nonce) {<a name="line.7585"></a>
+<span class="sourceLineNo">7586</span>      @Override<a name="line.7586"></a>
+<span class="sourceLineNo">7587</span>      public MiniBatchOperationInProgress&lt;Mutation&gt; lockRowsAndBuildMiniBatch(<a name="line.7587"></a>
+<span class="sourceLineNo">7588</span>          List&lt;RowLock&gt; acquiredRowLocks) throws IOException {<a name="line.7588"></a>
+<span class="sourceLineNo">7589</span>        RowLock prevRowLock = null;<a name="line.7589"></a>
+<span class="sourceLineNo">7590</span>        for (byte[] row : rowsToLock) {<a name="line.7590"></a>
+<span class="sourceLineNo">7591</span>          try {<a name="line.7591"></a>
+<span class="sourceLineNo">7592</span>            RowLock rowLock = region.getRowLockInternal(row, false, prevRowLock); // write lock<a name="line.7592"></a>
+<span class="sourceLineNo">7593</span>            if (rowLock != prevRowLock) {<a name="line.7593"></a>
+<span class="sourceLineNo">7594</span>              acquiredRowLocks.add(rowLock);<a name="line.7594"></a>
+<span class="sourceLineNo">7595</span>              prevRowLock = rowLock;<a name="line.7595"></a>
+<span class="sourceLineNo">7596</span>            }<a name="line.7596"></a>
+<span class="sourceLineNo">7597</span>          } catch (IOException ioe) {<a name="line.7597"></a>
+<span class="sourceLineNo">7598</span>            LOG.warn("Failed getting lock, row=" + Bytes.toStringBinary(row), ioe);<a name="line.7598"></a>
+<span class="sourceLineNo">7599</span>            throw ioe;<a name="line.7599"></a>
+<span class="sourceLineNo">7600</span>          }<a name="line.7600"></a>
+<span class="sourceLineNo">7601</span>        }<a name="line.7601"></a>
+<span class="sourceLineNo">7602</span>        return createMiniBatch(size(), size());<a name="line.7602"></a>
+<span class="sourceLineNo">7603</span>      }<a name="line.7603"></a>
+<span class="sourceLineNo">7604</span>    });<a name="line.7604"></a>
+<span class="sourceLineNo">7605</span>  }<a name="line.7605"></a>
+<span class="sourceLineNo">7606</span><a name="line.7606"></a>
+<span class="sourceLineNo">7607</span>  /**<a name="line.7607"></a>
+<span class="sourceLineNo">7608</span>   * @return statistics about the current load of the region<a name="line.7608"></a>
+<span class="sourceLineNo">7609</span>   */<a name="line.7609"></a>
+<span class="sourceLineNo">7610</span>  public ClientProtos.RegionLoadStats getLoadStatistics() {<a name="line.7610"></a>
+<span class="sourceLineNo">7611</span>    if (!regionStatsEnabled) {<a name="line.7611"></a>
+<span class="sourceLineNo">7612</span>      return null;<a name="line.7612"></a>
+<span class="sourceLineNo">7613</span>    }<a name="line.7613"></a>
+<span class="sourceLineNo">7614</span>    ClientProtos.RegionLoadStats.Builder stats = ClientProtos.RegionLoadStats.newBuilder();<a name="line.7614"></a>
+<span class="sourceLineNo">7615</span>    stats.setMemStoreLoad((int) (Math.min(100,<a name="line.7615"></a>
+<span class="sourceLineNo">7616</span>        (this.memStoreSizing.getMemStoreSize().getHeapSize() * 100) / this.memstoreFlushSize)));<a name="line.7616"></a>
+<span class="sourceLineNo">7617</span>    if (rsServices.getHeapMemoryManager() != null) {<a name="line.7617"></a>
+<span class="sourceLineNo">7618</span>      // the HeapMemoryManager uses -0.0 to signal a problem asking the JVM,<a name="line.7618"></a>
+<span class="sourceLineNo">7619</span>      // so we could just do the calculation below and we'll get a 0.<a name="line.7619"></a>
+<span class="sourceLineNo">7620</span>      // treating it as a special case analogous to no HMM instead so that it can be<a name="line.7620"></a>
+<span class="sourceLineNo">7621</span>      // programatically treated different from using &lt;1% of heap.<a name="line.7621"></a>
+<span class="sourceLineNo">7622</span>      final float occupancy = rsServices.getHeapMemoryManager().getHeapOccupancyPercent();<a name="line.7622"></a>
+<span class="sourceLineNo">7623</span>      if (occupancy != HeapMemoryManager.HEAP_OCCUPANCY_ERROR_VALUE) {<a name="line.7623"></a>
+<span class="sourceLineNo">7624</span>        stats.setHeapOccupancy((int)(occupancy * 100));<a name="line.7624"></a>
+<span class="sourceLineNo">7625</span>      }<a name="line.7625"></a>
+<span class="sourceLineNo">7626</span>    }<a name="line.7626"></a>
+<span class="sourceLineNo">7627</span>    stats.setCompactionPressure((int) (rsServices.getCompactionPressure() * 100 &gt; 100 ? 100<a name="line.7627"></a>
+<span class="sourceLineNo">7628</span>        : rsServices.getCompactionPressure() * 100));<a name="line.7628"></a>
+<span class="sourceLineNo">7629</span>    return stats.build();<a name="line.7629"></a>
+<span class="sourceLineNo">7630</span>  }<a name="line.7630"></a>
+<span class="sourceLineNo">7631</span><a name="line.7631"></a>
+<span class="sourceLineNo">7632</span>  @Override<a name="line.7632"></a>
+<span class="sourceLineNo">7633</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor) throws IOException {<a name="line.7633"></a>
+<span class="sourceLineNo">7634</span>    processRowsWithLocks(processor, rowProcessorTimeout, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7634"></a>
+<span class="sourceLineNo">7635</span>  }<a name="line.7635"></a>
+<span class="sourceLineNo">7636</span><a name="line.7636"></a>
+<span class="sourceLineNo">7637</span>  @Override<a name="line.7637"></a>
+<span class="sourceLineNo">7638</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long nonceGroup, long nonce)<a name="line.7638"></a>
+<span class="sourceLineNo">7639</span>      throws IOException {<a name="line.7639"></a>
+<span class="sourceLineNo">7640</span>    processRowsWithLocks(processor, rowProcessorTimeout, nonceGroup, nonce);<a name="line.7640"></a>
+<span class="sourceLineNo">7641</span>  }<a name="line.7641"></a>
+<span class="sourceLineNo">7642</span><a name="line.7642"></a>
+<span class="sourceLineNo">7643</span>  @Override<a name="line.7643"></a>
+<span class="sourceLineNo">7644</span>  public void processRowsWithLocks(RowProcessor&lt;?,?&gt; processor, long timeout,<a name="line.7644"></a>
+<span class="sourceLineNo">7645</span>      long nonceGroup, long nonce) throws IOException {<a name="line.7645"></a>
+<span class="sourceLineNo">7646</span>    for (byte[] row : processor.getRowsToLock()) {<a name="line.7646"></a>
+<span class="sourceLineNo">7647</span>      checkRow(row, "processRowsWithLocks");<a name="line.7647"></a>
 <span class="sourceLineNo">7648</span>    }<a name="line.7648"></a>
-<span class="sourceLineNo">7649</span>    checkResources();<a name="line.7649"></a>
-<span class="sourceLineNo">7650</span>    startRegionOperation();<a name="line.7650"></a>
-<span class="sourceLineNo">7651</span>    WALEdit walEdit = new WALEdit();<a name="line.7651"></a>
-<span class="sourceLineNo">7652</span><a name="line.7652"></a>
-<span class="sourceLineNo">7653</span>    // STEP 1. Run pre-process hook<a name="line.7653"></a>
-<span class="sourceLineNo">7654</span>    preProcess(processor, walEdit);<a name="line.7654"></a>
-<span class="sourceLineNo">7655</span>    // Short circuit the read only case<a name="line.7655"></a>
-<span class="sourceLineNo">7656</span>    if (processor.readOnly()) {<a name="line.7656"></a>
-<span class="sourceLineNo">7657</span>      try {<a name="line.7657"></a>
-<span class="sourceLineNo">7658</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7658"></a>
-<span class="sourceLineNo">7659</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7659"></a>
-<span class="sourceLineNo">7660</span>        processor.postProcess(this, walEdit, true);<a name="line.7660"></a>
-<span class="sourceLineNo">7661</span>      } finally {<a name="line.7661"></a>
-<span class="sourceLineNo">7662</span>        closeRegionOperation();<a name="line.7662"></a>
-<span class="sourceLineNo">7663</span>      }<a name="line.7663"></a>
-<span class="sourceLineNo">7664</span>      return;<a name="line.7664"></a>
-<span class="sourceLineNo">7665</span>    }<a name="line.7665"></a>
-<span class="sourceLineNo">7666</span><a name="line.7666"></a>
-<span class="sourceLineNo">7667</span>    boolean locked = false;<a name="line.7667"></a>
-<span class="sourceLineNo">7668</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7668"></a>
-<span class="sourceLineNo">7669</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7669"></a>
-<span class="sourceLineNo">7670</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7670"></a>
-<span class="sourceLineNo">7671</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7671"></a>
-<span class="sourceLineNo">7672</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7672"></a>
-<span class="sourceLineNo">7673</span>    WriteEntry writeEntry = null;<a name="line.7673"></a>
-<span class="sourceLineNo">7674</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7674"></a>
-<span class="sourceLineNo">7675</span>    try {<a name="line.7675"></a>
-<span class="sourceLineNo">7676</span>      boolean success = false;<a name="line.7676"></a>
-<span class="sourceLineNo">7677</span>      try {<a name="line.7677"></a>
-<span class="sourceLineNo">7678</span>        // STEP 2. Acquire the row lock(s)<a name="line.7678"></a>
-<span class="sourceLineNo">7679</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7679"></a>
-<span class="sourceLineNo">7680</span>        RowLock prevRowLock = null;<a name="line.7680"></a>
-<span class="sourceLineNo">7681</span>        for (byte[] row : rowsToLock) {<a name="line.7681"></a>
-<span class="sourceLineNo">7682</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7682"></a>
-<span class="sourceLineNo">7683</span>          // use a writer lock for mixed reads and writes<a name="line.7683"></a>
-<span class="sourceLineNo">7684</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7684"></a>
-<span class="sourceLineNo">7685</span>          if (rowLock != prevRowLock) {<a name="line.7685"></a>
-<span class="sourceLineNo">7686</span>            acquiredRowLocks.add(rowLock);<a name="line.7686"></a>
-<span class="sourceLineNo">7687</span>            prevRowLock = rowLock;<a name="line.7687"></a>
-<span class="sourceLineNo">7688</span>          }<a name="line.7688"></a>
-<span class="sourceLineNo">7689</span>        }<a name="line.7689"></a>
-<span class="sourceLineNo">7690</span>        // STEP 3. Region lock<a name="line.7690"></a>
-<span class="sourceLineNo">7691</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7691"></a>
-<span class="sourceLineNo">7692</span>        locked = true;<a name="line.7692"></a>
-<span class="sourceLineNo">7693</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7693"></a>
-<span class="sourceLineNo">7694</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7694"></a>
-<span class="sourceLineNo">7695</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7695"></a>
-<span class="sourceLineNo">7696</span>        if (!mutations.isEmpty()) {<a name="line.7696"></a>
-<span class="sourceLineNo">7697</span>          writeRequestsCount.add(mutations.size());<a name="line.7697"></a>
-<span class="sourceLineNo">7698</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7698"></a>
-<span class="sourceLineNo">7699</span>          processor.preBatchMutate(this, walEdit);<a name="line.7699"></a>
-<span class="sourceLineNo">7700</span><a name="line.7700"></a>
-<span class="sourceLineNo">7701</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7701"></a>
-<span class="sourceLineNo">7702</span>          if (!walEdit.isEmpty()) {<a name="line.7702"></a>
-<span class="sourceLineNo">7703</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7703"></a>
-<span class="sourceLineNo">7704</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7704"></a>
-<span class="sourceLineNo">7705</span>          } else {<a name="line.7705"></a>
-<span class="sourceLineNo">7706</span>            // We are here if WAL is being skipped.<a name="line.7706"></a>
-<span class="sourceLineNo">7707</span>            writeEntry = this.mvcc.begin();<a name="line.7707"></a>
-<span class="sourceLineNo">7708</span>          }<a name="line.7708"></a>
-<span class="sourceLineNo">7709</span><a name="line.7709"></a>
-<span class="sourceLineNo">7710</span>          // STEP 7. Apply to memstore<a name="line.7710"></a>
-<span class="sourceLineNo">7711</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7711"></a>
-<span class="sourceLineNo">7712</span>          for (Mutation m : mutations) {<a name="line.7712"></a>
-<span class="sourceLineNo">7713</span>            // Handle any tag based cell features.<a name="line.7713"></a>
-<span class="sourceLineNo">7714</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7714"></a>
-<span class="sourceLineNo">7715</span>            // so tags go into WAL?<a name="line.7715"></a>
-<span class="sourceLineNo">7716</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7716"></a>
-<span class="sourceLineNo">7717</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7717"></a>
-<span class="sourceLineNo">7718</span>              Cell cell = cellScanner.current();<a name="line.7718"></a>
-<span class="sourceLineNo">7719</span>              if (walEdit.isEmpty()) {<a name="line.7719"></a>
-<span class="sourceLineNo">7720</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7720"></a>
-<span class="sourceLineNo">7721</span>                // If no WAL, need to stamp it here.<a name="line.7721"></a>
-<span class="sourceLineNo">7722</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7722"></a>
-<span class="sourceLineNo">7723</span>              }<a name="line.7723"></a>
-<span class="sourceLineNo">7724</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7724"></a>
-<span class="sourceLineNo">7725</span>            }<a name="line.7725"></a>
-<span class="sourceLineNo">7726</span>          }<a name="line.7726"></a>
-<span class="sourceLineNo">7727</span><a name="line.7727"></a>
-<span class="sourceLineNo">7728</span>          // STEP 8. call postBatchMutate hook<a name="line.7728"></a>
-<span class="sourceLineNo">7729</span>          processor.postBatchMutate(this);<a name="line.7729"></a>
+<span class="sourceLineNo">7649</span>    if (!processor.readOnly()) {<a name="line.7649"></a>
+<span class="sourceLineNo">7650</span>      checkReadOnly();<a name="line.7650"></a>
+<span class="sourceLineNo">7651</span>    }<a name="line.7651"></a>
+<span class="sourceLineNo">7652</span>    checkResources();<a name="line.7652"></a>
+<span class="sourceLineNo">7653</span>    startRegionOperation();<a name="line.7653"></a>
+<span class="sourceLineNo">7654</span>    WALEdit walEdit = new WALEdit();<a name="line.7654"></a>
+<span class="sourceLineNo">7655</span><a name="line.7655"></a>
+<span class="sourceLineNo">7656</span>    // STEP 1. Run pre-process hook<a name="line.7656"></a>
+<span class="sourceLineNo">7657</span>    preProcess(processor, walEdit);<a name="line.7657"></a>
+<span class="sourceLineNo">7658</span>    // Short circuit the read only case<a name="line.7658"></a>
+<span class="sourceLineNo">7659</span>    if (processor.readOnly()) {<a name="line.7659"></a>
+<span class="sourceLineNo">7660</span>      try {<a name="line.7660"></a>
+<span class="sourceLineNo">7661</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7661"></a>
+<span class="sourceLineNo">7662</span>        doProcessRowWithTimeout(processor, now, this, null, null, timeout);<a name="line.7662"></a>
+<span class="sourceLineNo">7663</span>        processor.postProcess(this, walEdit, true);<a name="line.7663"></a>
+<span class="sourceLineNo">7664</span>      } finally {<a name="line.7664"></a>
+<span class="sourceLineNo">7665</span>        closeRegionOperation();<a name="line.7665"></a>
+<span class="sourceLineNo">7666</span>      }<a name="line.7666"></a>
+<span class="sourceLineNo">7667</span>      return;<a name="line.7667"></a>
+<span class="sourceLineNo">7668</span>    }<a name="line.7668"></a>
+<span class="sourceLineNo">7669</span><a name="line.7669"></a>
+<span class="sourceLineNo">7670</span>    boolean locked = false;<a name="line.7670"></a>
+<span class="sourceLineNo">7671</span>    List&lt;RowLock&gt; acquiredRowLocks = null;<a name="line.7671"></a>
+<span class="sourceLineNo">7672</span>    List&lt;Mutation&gt; mutations = new ArrayList&lt;&gt;();<a name="line.7672"></a>
+<span class="sourceLineNo">7673</span>    Collection&lt;byte[]&gt; rowsToLock = processor.getRowsToLock();<a name="line.7673"></a>
+<span class="sourceLineNo">7674</span>    // This is assigned by mvcc either explicity in the below or in the guts of the WAL append<a name="line.7674"></a>
+<span class="sourceLineNo">7675</span>    // when it assigns the edit a sequencedid (A.K.A the mvcc write number).<a name="line.7675"></a>
+<span class="sourceLineNo">7676</span>    WriteEntry writeEntry = null;<a name="line.7676"></a>
+<span class="sourceLineNo">7677</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7677"></a>
+<span class="sourceLineNo">7678</span>    try {<a name="line.7678"></a>
+<span class="sourceLineNo">7679</span>      boolean success = false;<a name="line.7679"></a>
+<span class="sourceLineNo">7680</span>      try {<a name="line.7680"></a>
+<span class="sourceLineNo">7681</span>        // STEP 2. Acquire the row lock(s)<a name="line.7681"></a>
+<span class="sourceLineNo">7682</span>        acquiredRowLocks = new ArrayList&lt;&gt;(rowsToLock.size());<a name="line.7682"></a>
+<span class="sourceLineNo">7683</span>        RowLock prevRowLock = null;<a name="line.7683"></a>
+<span class="sourceLineNo">7684</span>        for (byte[] row : rowsToLock) {<a name="line.7684"></a>
+<span class="sourceLineNo">7685</span>          // Attempt to lock all involved rows, throw if any lock times out<a name="line.7685"></a>
+<span class="sourceLineNo">7686</span>          // use a writer lock for mixed reads and writes<a name="line.7686"></a>
+<span class="sourceLineNo">7687</span>          RowLock rowLock = getRowLockInternal(row, false, prevRowLock);<a name="line.7687"></a>
+<span class="sourceLineNo">7688</span>          if (rowLock != prevRowLock) {<a name="line.7688"></a>
+<span class="sourceLineNo">7689</span>            acquiredRowLocks.add(rowLock);<a name="line.7689"></a>
+<span class="sourceLineNo">7690</span>            prevRowLock = rowLock;<a name="line.7690"></a>
+<span class="sourceLineNo">7691</span>          }<a name="line.7691"></a>
+<span class="sourceLineNo">7692</span>        }<a name="line.7692"></a>
+<span class="sourceLineNo">7693</span>        // STEP 3. Region lock<a name="line.7693"></a>
+<span class="sourceLineNo">7694</span>        lock(this.updatesLock.readLock(), acquiredRowLocks.isEmpty() ? 1 : acquiredRowLocks.size());<a name="line.7694"></a>
+<span class="sourceLineNo">7695</span>        locked = true;<a name="line.7695"></a>
+<span class="sourceLineNo">7696</span>        long now = EnvironmentEdgeManager.currentTime();<a name="line.7696"></a>
+<span class="sourceLineNo">7697</span>        // STEP 4. Let the processor scan the rows, generate mutations and add waledits<a name="line.7697"></a>
+<span class="sourceLineNo">7698</span>        doProcessRowWithTimeout(processor, now, this, mutations, walEdit, timeout);<a name="line.7698"></a>
+<span class="sourceLineNo">7699</span>        if (!mutations.isEmpty()) {<a name="line.7699"></a>
+<span class="sourceLineNo">7700</span>          writeRequestsCount.add(mutations.size());<a name="line.7700"></a>
+<span class="sourceLineNo">7701</span>          // STEP 5. Call the preBatchMutate hook<a name="line.7701"></a>
+<span class="sourceLineNo">7702</span>          processor.preBatchMutate(this, walEdit);<a name="line.7702"></a>
+<span class="sourceLineNo">7703</span><a name="line.7703"></a>
+<span class="sourceLineNo">7704</span>          // STEP 6. Append and sync if walEdit has data to write out.<a name="line.7704"></a>
+<span class="sourceLineNo">7705</span>          if (!walEdit.isEmpty()) {<a name="line.7705"></a>
+<span class="sourceLineNo">7706</span>            writeEntry = doWALAppend(walEdit, getEffectiveDurability(processor.useDurability()),<a name="line.7706"></a>
+<span class="sourceLineNo">7707</span>                processor.getClusterIds(), now, nonceGroup, nonce);<a name="line.7707"></a>
+<span class="sourceLineNo">7708</span>          } else {<a name="line.7708"></a>
+<span class="sourceLineNo">7709</span>            // We are here if WAL is being skipped.<a name="line.7709"></a>
+<span class="sourceLineNo">7710</span>            writeEntry = this.mvcc.begin();<a name="line.7710"></a>
+<span class="sourceLineNo">7711</span>          }<a name="line.7711"></a>
+<span class="sourceLineNo">7712</span><a name="line.7712"></a>
+<span class="sourceLineNo">7713</span>          // STEP 7. Apply to memstore<a name="line.7713"></a>
+<span class="sourceLineNo">7714</span>          long sequenceId = writeEntry.getWriteNumber();<a name="line.7714"></a>
+<span class="sourceLineNo">7715</span>          for (Mutation m : mutations) {<a name="line.7715"></a>
+<span class="sourceLineNo">7716</span>            // Handle any tag based cell features.<a name="line.7716"></a>
+<span class="sourceLineNo">7717</span>            // TODO: Do we need to call rewriteCellTags down in applyToMemStore()? Why not before<a name="line.7717"></a>
+<span class="sourceLineNo">7718</span>            // so tags go into WAL?<a name="line.7718"></a>
+<span class="sourceLineNo">7719</span>            rewriteCellTags(m.getFamilyCellMap(), m);<a name="line.7719"></a>
+<span class="sourceLineNo">7720</span>            for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {<a name="line.7720"></a>
+<span class="sourceLineNo">7721</span>              Cell cell = cellScanner.current();<a name="line.7721"></a>
+<span class="sourceLineNo">7722</span>              if (walEdit.isEmpty()) {<a name="line.7722"></a>
+<span class="sourceLineNo">7723</span>                // If walEdit is empty, we put nothing in WAL. WAL stamps Cells with sequence id.<a name="line.7723"></a>
+<span class="sourceLineNo">7724</span>                // If no WAL, need to stamp it here.<a name="line.7724"></a>
+<span class="sourceLineNo">7725</span>                PrivateCellUtil.setSequenceId(cell, sequenceId);<a name="line.7725"></a>
+<span class="sourceLineNo">7726</span>              }<a name="line.7726"></a>
+<span class="sourceLineNo">7727</span>              applyToMemStore(getStore(cell), cell, memstoreAccounting);<a name="line.7727"></a>
+<span class="sourceLineNo">7728</span>            }<a name="line.7728"></a>
+<span class="sourceLineNo">7729</span>          }<a name="line.7729"></a>
 <span class="sourceLineNo">7730</span><a name="line.7730"></a>
-<span class="sourceLineNo">7731</span>          // STEP 9. Complete mvcc.<a name="line.7731"></a>
-<span class="sourceLineNo">7732</span>          mvcc.completeAndWait(writeEntry);<a name="line.7732"></a>
-<span class="sourceLineNo">7733</span>          writeEntry = null;<a name="line.7733"></a>
-<span class="sourceLineNo">7734</span><a name="line.7734"></a>
-<span class="sourceLineNo">7735</span>          // STEP 10. Release region lock<a name="line.7735"></a>
-<span class="sourceLineNo">7736</span>          if (locked) {<a name="line.7736"></a>
-<span class="sourceLineNo">7737</span>            this.updatesLock.readLock().unlock();<a name="line.7737"></a>
-<span class="sourceLineNo">7738</span>            locked = false;<a name="line.7738"></a>
-<span class="sourceLineNo">7739</span>          }<a name="line.7739"></a>
-<span class="sourceLineNo">7740</span><a name="line.7740"></a>
-<span class="sourceLineNo">7741</span>          // STEP 11. Release row lock(s)<a name="line.7741"></a>
-<span class="sourceLineNo">7742</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7742"></a>
-<span class="sourceLineNo">7743</span>        }<a name="line.7743"></a>
-<span class="sourceLineNo">7744</span>        success = true;<a name="line.7744"></a>
-<span class="sourceLineNo">7745</span>      } finally {<a name="line.7745"></a>
-<span class="sourceLineNo">7746</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7746"></a>
-<span class="sourceLineNo">7747</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7747"></a>
-<span class="sourceLineNo">7748</span>        if (locked) {<a name="line.7748"></a>
-<span class="sourceLineNo">7749</span>          this.updatesLock.readLock().unlock();<a name="line.7749"></a>
-<span class="sourceLineNo">7750</span>        }<a name="line.7750"></a>
-<span class="sourceLineNo">7751</span>        // release locks if some were acquired but another timed out<a name="line.7751"></a>
-<span class="sourceLineNo">7752</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7752"></a>
-<span class="sourceLineNo">7753</span>      }<a name="line.7753"></a>
-<span class="sourceLineNo">7754</span><a name="line.7754"></a>
-<span class="sourceLineNo">7755</span>      // 12. Run post-process hook<a name="line.7755"></a>
-<span class="sourceLineNo">7756</span>      processor.postProcess(this, walEdit, success);<a name="line.7756"></a>
-<span class="sourceLineNo">7757</span>    } finally {<a name="line.7757"></a>
-<span class="sourceLineNo">7758</span>      closeRegionOperation();<a name="line.7758"></a>
-<span class="sourceLineNo">7759</span>      if (!mutations.isEmpty()) {<a name="line.7759"></a>
-<span class="sourceLineNo">7760</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7760"></a>
-<span class="sourceLineNo">7761</span>        requestFlushIfNeeded();<a name="line.7761"></a>
-<span class="sourceLineNo">7762</span>      }<a name="line.7762"></a>
-<span class="sourceLineNo">7763</span>    }<a name="line.7763"></a>
-<span class="sourceLineNo">7764</span>  }<a name="line.7764"></a>
-<span class="sourceLineNo">7765</span><a name="line.7765"></a>
-<span class="sourceLineNo">7766</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7766"></a>
-<span class="sourceLineNo">7767</span>  throws IOException {<a name="line.7767"></a>
-<span class="sourceLineNo">7768</span>    try {<a name="line.7768"></a>
-<span class="sourceLineNo">7769</span>      processor.preProcess(this, walEdit);<a name="line.7769"></a>
-<span class="sourceLineNo">7770</span>    } catch (IOException e) {<a name="line.7770"></a>
-<span class="sourceLineNo">7771</span>      closeRegionOperation();<a name="line.7771"></a>
-<span class="sourceLineNo">7772</span>      throw e;<a name="line.7772"></a>
-<span class="sourceLineNo">7773</span>    }<a name="line.7773"></a>
-<span class="sourceLineNo">7774</span>  }<a name="line.7774"></a>
-<span class="sourceLineNo">7775</span><a name="line.7775"></a>
-<span class="sourceLineNo">7776</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7776"></a>
-<span class="sourceLineNo">7777</span>                                       final long now,<a name="line.7777"></a>
-<span class="sourceLineNo">7778</span>                                       final HRegion region,<a name="line.7778"></a>
-<span class="sourceLineNo">7779</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7779"></a>
-<span class="sourceLineNo">7780</span>                                       final WALEdit walEdit,<a name="line.7780"></a>
-<span class="sourceLineNo">7781</span>                                       final long timeout) throws IOException {<a name="line.7781"></a>
-<span class="sourceLineNo">7782</span>    // Short circuit the no time bound case.<a name="line.7782"></a>
-<span class="sourceLineNo">7783</span>    if (timeout &lt; 0) {<a name="line.7783"></a>
-<span class="sourceLineNo">7784</span>      try {<a name="line.7784"></a>
-<span class="sourceLineNo">7785</span>        processor.process(now, region, mutations, walEdit);<a name="line.7785"></a>
-<span class="sourceLineNo">7786</span>      } catch (IOException e) {<a name="line.7786"></a>
-<span class="sourceLineNo">7787</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7787"></a>
-<span class="sourceLineNo">7788</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7788"></a>
-<span class="sourceLineNo">7789</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7789"></a>
-<span class="sourceLineNo">7790</span>            " throws Exception" + row, e);<a name="line.7790"></a>
-<span class="sourceLineNo">7791</span>        throw e;<a name="line.7791"></a>
-<span class="sourceLineNo">7792</span>      }<a name="line.7792"></a>
-<span class="sourceLineNo">7793</span>      return;<a name="line.7793"></a>
-<span class="sourceLineNo">7794</span>    }<a name="line.7794"></a>
-<span class="sourceLineNo">7795</span><a name="line.7795"></a>
-<span class="sourceLineNo">7796</span>    // Case with time bound<a name="line.7796"></a>
-<span class="sourceLineNo">7797</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7797"></a>
-<span class="sourceLineNo">7798</span>        @Override<a name="line.7798"></a>
-<span class="sourceLineNo">7799</span>        public Void call() throws IOException {<a name="line.7799"></a>
-<span class="sourceLineNo">7800</span>          try {<a name="line.7800"></a>
-<span class="sourceLineNo">7801</span>            processor.process(now, region, mutations, walEdit);<a name="line.7801"></a>
-<span class="sourceLineNo">7802</span>            return null;<a name="line.7802"></a>
-<span class="sourceLineNo">7803</span>          } catch (IOException e) {<a name="line.7803"></a>
-<span class="sourceLineNo">7804</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7804"></a>
-<span class="sourceLineNo">7805</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7805"></a>
-<span class="sourceLineNo">7806</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7806"></a>
-<span class="sourceLineNo">7807</span>                " throws Exception" + row, e);<a name="line.7807"></a>
-<span class="sourceLineNo">7808</span>            throw e;<a name="line.7808"></a>
-<span class="sourceLineNo">7809</span>          }<a name="line.7809"></a>
-<span class="sourceLineNo">7810</span>        }<a name="line.7810"></a>
-<span class="sourceLineNo">7811</span>      });<a name="line.7811"></a>
-<span class="sourceLineNo">7812</span>    rowProcessorExecutor.execute(task);<a name="line.7812"></a>
-<span class="sourceLineNo">7813</span>    try {<a name="line.7813"></a>
-<span class="sourceLineNo">7814</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7814"></a>
-<span class="sourceLineNo">7815</span>    } catch (TimeoutException te) {<a name="line.7815"></a>
-<span class="sourceLineNo">7816</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7816"></a>
-<span class="sourceLineNo">7817</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7817"></a>
-<span class="sourceLineNo">7818</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7818"></a>
-<span class="sourceLineNo">7819</span>      throw new IOException(te);<a name="line.7819"></a>
-<span class="sourceLineNo">7820</span>    } catch (Exception e) {<a name="line.7820"></a>
-<span class="sourceLineNo">7821</span>      throw new IOException(e);<a name="line.7821"></a>
-<span class="sourceLineNo">7822</span>    }<a name="line.7822"></a>
-<span class="sourceLineNo">7823</span>  }<a name="line.7823"></a>
-<span class="sourceLineNo">7824</span><a name="line.7824"></a>
-<span class="sourceLineNo">7825</span>  @Override<a name="line.7825"></a>
-<span class="sourceLineNo">7826</span>  public Result append(Append append) throws IOException {<a name="line.7826"></a>
-<span class="sourceLineNo">7827</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7827"></a>
-<span class="sourceLineNo">7828</span>  }<a name="line.7828"></a>
-<span class="sourceLineNo">7829</span><a name="line.7829"></a>
-<span class="sourceLineNo">7830</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7830"></a>
-<span class="sourceLineNo">7831</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7831"></a>
-<span class="sourceLineNo">7832</span>  }<a name="line.7832"></a>
-<span class="sourceLineNo">7833</span><a name="line.7833"></a>
-<span class="sourceLineNo">7834</span>  @Override<a name="line.7834"></a>
-<span class="sourceLineNo">7835</span>  public Result increment(Increment increment) throws IOException {<a name="line.7835"></a>
-<span class="sourceLineNo">7836</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7836"></a>
-<span class="sourceLineNo">7837</span>  }<a name="line.7837"></a>
-<span class="sourceLineNo">7838</span><a name="line.7838"></a>
-<span class="sourceLineNo">7839</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7839"></a>
-<span class="sourceLineNo">7840</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7840"></a>
-<span class="sourceLineNo">7841</span>  }<a name="line.7841"></a>
-<span class="sourceLineNo">7842</span><a name="line.7842"></a>
-<span class="sourceLineNo">7843</span>  /**<a name="line.7843"></a>
-<span class="sourceLineNo">7844</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7844"></a>
-<span class="sourceLineNo">7845</span>   *<a name="line.7845"></a>
-<span class="sourceLineNo">7846</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7846"></a>
-<span class="sourceLineNo">7847</span>   * append the deltas to the current Cell values.<a name="line.7847"></a>
+<span class="sourceLineNo">7731</span>          // STEP 8. call postBatchMutate hook<a name="line.7731"></a>
+<span class="sourceLineNo">7732</span>          processor.postBatchMutate(this);<a name="line.7732"></a>
+<span class="sourceLineNo">7733</span><a name="line.7733"></a>
+<span class="sourceLineNo">7734</span>          // STEP 9. Complete mvcc.<a name="line.7734"></a>
+<span class="sourceLineNo">7735</span>          mvcc.completeAndWait(writeEntry);<a name="line.7735"></a>
+<span class="sourceLineNo">7736</span>          writeEntry = null;<a name="line.7736"></a>
+<span class="sourceLineNo">7737</span><a name="line.7737"></a>
+<span class="sourceLineNo">7738</span>          // STEP 10. Release region lock<a name="line.7738"></a>
+<span class="sourceLineNo">7739</span>          if (locked) {<a name="line.7739"></a>
+<span class="sourceLineNo">7740</span>            this.updatesLock.readLock().unlock();<a name="line.7740"></a>
+<span class="sourceLineNo">7741</span>            locked = false;<a name="line.7741"></a>
+<span class="sourceLineNo">7742</span>          }<a name="line.7742"></a>
+<span class="sourceLineNo">7743</span><a name="line.7743"></a>
+<span class="sourceLineNo">7744</span>          // STEP 11. Release row lock(s)<a name="line.7744"></a>
+<span class="sourceLineNo">7745</span>          releaseRowLocks(acquiredRowLocks);<a name="line.7745"></a>
+<span class="sourceLineNo">7746</span>        }<a name="line.7746"></a>
+<span class="sourceLineNo">7747</span>        success = true;<a name="line.7747"></a>
+<span class="sourceLineNo">7748</span>      } finally {<a name="line.7748"></a>
+<span class="sourceLineNo">7749</span>        // Call complete rather than completeAndWait because we probably had error if walKey != null<a name="line.7749"></a>
+<span class="sourceLineNo">7750</span>        if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7750"></a>
+<span class="sourceLineNo">7751</span>        if (locked) {<a name="line.7751"></a>
+<span class="sourceLineNo">7752</span>          this.updatesLock.readLock().unlock();<a name="line.7752"></a>
+<span class="sourceLineNo">7753</span>        }<a name="line.7753"></a>
+<span class="sourceLineNo">7754</span>        // release locks if some were acquired but another timed out<a name="line.7754"></a>
+<span class="sourceLineNo">7755</span>        releaseRowLocks(acquiredRowLocks);<a name="line.7755"></a>
+<span class="sourceLineNo">7756</span>      }<a name="line.7756"></a>
+<span class="sourceLineNo">7757</span><a name="line.7757"></a>
+<span class="sourceLineNo">7758</span>      // 12. Run post-process hook<a name="line.7758"></a>
+<span class="sourceLineNo">7759</span>      processor.postProcess(this, walEdit, success);<a name="line.7759"></a>
+<span class="sourceLineNo">7760</span>    } finally {<a name="line.7760"></a>
+<span class="sourceLineNo">7761</span>      closeRegionOperation();<a name="line.7761"></a>
+<span class="sourceLineNo">7762</span>      if (!mutations.isEmpty()) {<a name="line.7762"></a>
+<span class="sourceLineNo">7763</span>        this.incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7763"></a>
+<span class="sourceLineNo">7764</span>        requestFlushIfNeeded();<a name="line.7764"></a>
+<span class="sourceLineNo">7765</span>      }<a name="line.7765"></a>
+<span class="sourceLineNo">7766</span>    }<a name="line.7766"></a>
+<span class="sourceLineNo">7767</span>  }<a name="line.7767"></a>
+<span class="sourceLineNo">7768</span><a name="line.7768"></a>
+<span class="sourceLineNo">7769</span>  private void preProcess(final RowProcessor&lt;?,?&gt; processor, final WALEdit walEdit)<a name="line.7769"></a>
+<span class="sourceLineNo">7770</span>  throws IOException {<a name="line.7770"></a>
+<span class="sourceLineNo">7771</span>    try {<a name="line.7771"></a>
+<span class="sourceLineNo">7772</span>      processor.preProcess(this, walEdit);<a name="line.7772"></a>
+<span class="sourceLineNo">7773</span>    } catch (IOException e) {<a name="line.7773"></a>
+<span class="sourceLineNo">7774</span>      closeRegionOperation();<a name="line.7774"></a>
+<span class="sourceLineNo">7775</span>      throw e;<a name="line.7775"></a>
+<span class="sourceLineNo">7776</span>    }<a name="line.7776"></a>
+<span class="sourceLineNo">7777</span>  }<a name="line.7777"></a>
+<span class="sourceLineNo">7778</span><a name="line.7778"></a>
+<span class="sourceLineNo">7779</span>  private void doProcessRowWithTimeout(final RowProcessor&lt;?,?&gt; processor,<a name="line.7779"></a>
+<span class="sourceLineNo">7780</span>                                       final long now,<a name="line.7780"></a>
+<span class="sourceLineNo">7781</span>                                       final HRegion region,<a name="line.7781"></a>
+<span class="sourceLineNo">7782</span>                                       final List&lt;Mutation&gt; mutations,<a name="line.7782"></a>
+<span class="sourceLineNo">7783</span>                                       final WALEdit walEdit,<a name="line.7783"></a>
+<span class="sourceLineNo">7784</span>                                       final long timeout) throws IOException {<a name="line.7784"></a>
+<span class="sourceLineNo">7785</span>    // Short circuit the no time bound case.<a name="line.7785"></a>
+<span class="sourceLineNo">7786</span>    if (timeout &lt; 0) {<a name="line.7786"></a>
+<span class="sourceLineNo">7787</span>      try {<a name="line.7787"></a>
+<span class="sourceLineNo">7788</span>        processor.process(now, region, mutations, walEdit);<a name="line.7788"></a>
+<span class="sourceLineNo">7789</span>      } catch (IOException e) {<a name="line.7789"></a>
+<span class="sourceLineNo">7790</span>        String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7790"></a>
+<span class="sourceLineNo">7791</span>          " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7791"></a>
+<span class="sourceLineNo">7792</span>        LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7792"></a>
+<span class="sourceLineNo">7793</span>            " throws Exception" + row, e);<a name="line.7793"></a>
+<span class="sourceLineNo">7794</span>        throw e;<a name="line.7794"></a>
+<span class="sourceLineNo">7795</span>      }<a name="line.7795"></a>
+<span class="sourceLineNo">7796</span>      return;<a name="line.7796"></a>
+<span class="sourceLineNo">7797</span>    }<a name="line.7797"></a>
+<span class="sourceLineNo">7798</span><a name="line.7798"></a>
+<span class="sourceLineNo">7799</span>    // Case with time bound<a name="line.7799"></a>
+<span class="sourceLineNo">7800</span>    FutureTask&lt;Void&gt; task = new FutureTask&lt;&gt;(new Callable&lt;Void&gt;() {<a name="line.7800"></a>
+<span class="sourceLineNo">7801</span>        @Override<a name="line.7801"></a>
+<span class="sourceLineNo">7802</span>        public Void call() throws IOException {<a name="line.7802"></a>
+<span class="sourceLineNo">7803</span>          try {<a name="line.7803"></a>
+<span class="sourceLineNo">7804</span>            processor.process(now, region, mutations, walEdit);<a name="line.7804"></a>
+<span class="sourceLineNo">7805</span>            return null;<a name="line.7805"></a>
+<span class="sourceLineNo">7806</span>          } catch (IOException e) {<a name="line.7806"></a>
+<span class="sourceLineNo">7807</span>            String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7807"></a>
+<span class="sourceLineNo">7808</span>              " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7808"></a>
+<span class="sourceLineNo">7809</span>            LOG.warn("RowProcessor:" + processor.getClass().getName() +<a name="line.7809"></a>
+<span class="sourceLineNo">7810</span>                " throws Exception" + row, e);<a name="line.7810"></a>
+<span class="sourceLineNo">7811</span>            throw e;<a name="line.7811"></a>
+<span class="sourceLineNo">7812</span>          }<a name="line.7812"></a>
+<span class="sourceLineNo">7813</span>        }<a name="line.7813"></a>
+<span class="sourceLineNo">7814</span>      });<a name="line.7814"></a>
+<span class="sourceLineNo">7815</span>    rowProcessorExecutor.execute(task);<a name="line.7815"></a>
+<span class="sourceLineNo">7816</span>    try {<a name="line.7816"></a>
+<span class="sourceLineNo">7817</span>      task.get(timeout, TimeUnit.MILLISECONDS);<a name="line.7817"></a>
+<span class="sourceLineNo">7818</span>    } catch (TimeoutException te) {<a name="line.7818"></a>
+<span class="sourceLineNo">7819</span>      String row = processor.getRowsToLock().isEmpty() ? "" :<a name="line.7819"></a>
+<span class="sourceLineNo">7820</span>        " on row(s):" + Bytes.toStringBinary(processor.getRowsToLock().iterator().next()) + "...";<a name="line.7820"></a>
+<span class="sourceLineNo">7821</span>      LOG.error("RowProcessor timeout:" + timeout + " ms" + row);<a name="line.7821"></a>
+<span class="sourceLineNo">7822</span>      throw new IOException(te);<a name="line.7822"></a>
+<span class="sourceLineNo">7823</span>    } catch (Exception e) {<a name="line.7823"></a>
+<span class="sourceLineNo">7824</span>      throw new IOException(e);<a name="line.7824"></a>
+<span class="sourceLineNo">7825</span>    }<a name="line.7825"></a>
+<span class="sourceLineNo">7826</span>  }<a name="line.7826"></a>
+<span class="sourceLineNo">7827</span><a name="line.7827"></a>
+<span class="sourceLineNo">7828</span>  @Override<a name="line.7828"></a>
+<span class="sourceLineNo">7829</span>  public Result append(Append append) throws IOException {<a name="line.7829"></a>
+<span class="sourceLineNo">7830</span>    return append(append, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7830"></a>
+<span class="sourceLineNo">7831</span>  }<a name="line.7831"></a>
+<span class="sourceLineNo">7832</span><a name="line.7832"></a>
+<span class="sourceLineNo">7833</span>  public Result append(Append mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7833"></a>
+<span class="sourceLineNo">7834</span>    return doDelta(Operation.APPEND, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7834"></a>
+<span class="sourceLineNo">7835</span>  }<a name="line.7835"></a>
+<span class="sourceLineNo">7836</span><a name="line.7836"></a>
+<span class="sourceLineNo">7837</span>  @Override<a name="line.7837"></a>
+<span class="sourceLineNo">7838</span>  public Result increment(Increment increment) throws IOException {<a name="line.7838"></a>
+<span class="sourceLineNo">7839</span>    return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);<a name="line.7839"></a>
+<span class="sourceLineNo">7840</span>  }<a name="line.7840"></a>
+<span class="sourceLineNo">7841</span><a name="line.7841"></a>
+<span class="sourceLineNo">7842</span>  public Result increment(Increment mutation, long nonceGroup, long nonce) throws IOException {<a name="line.7842"></a>
+<span class="sourceLineNo">7843</span>    return doDelta(Operation.INCREMENT, mutation, nonceGroup, nonce, mutation.isReturnResults());<a name="line.7843"></a>
+<span class="sourceLineNo">7844</span>  }<a name="line.7844"></a>
+<span class="sourceLineNo">7845</span><a name="line.7845"></a>
+<span class="sourceLineNo">7846</span>  /**<a name="line.7846"></a>
+<span class="sourceLineNo">7847</span>   * Add "deltas" to Cells. Deltas are increments or appends. Switch on &lt;code&gt;op&lt;/code&gt;.<a name="line.7847"></a>
 <span class="sourceLineNo">7848</span>   *<a name="line.7848"></a>
-<span class="sourceLineNo">7849</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7849"></a>
-<span class="sourceLineNo">7850</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7850"></a>
-<span class="sourceLineNo">7851</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7851"></a>
-<span class="sourceLineNo">7852</span>   */<a name="line.7852"></a>
-<span class="sourceLineNo">7853</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7853"></a>
-<span class="sourceLineNo">7854</span>      boolean returnResults) throws IOException {<a name="line.7854"></a>
-<span class="sourceLineNo">7855</span>    checkReadOnly();<a name="line.7855"></a>
-<span class="sourceLineNo">7856</span>    checkResources();<a name="line.7856"></a>
-<span class="sourceLineNo">7857</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7857"></a>
-<span class="sourceLineNo">7858</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7858"></a>
-<span class="sourceLineNo">7859</span>    this.writeRequestsCount.increment();<a name="line.7859"></a>
-<span class="sourceLineNo">7860</span>    WriteEntry writeEntry = null;<a name="line.7860"></a>
-<span class="sourceLineNo">7861</span>    startRegionOperation(op);<a name="line.7861"></a>
-<span class="sourceLineNo">7862</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7862"></a>
-<span class="sourceLineNo">7863</span>    RowLock rowLock = null;<a name="line.7863"></a>
-<span class="sourceLineNo">7864</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7864"></a>
-<span class="sourceLineNo">7865</span>    try {<a name="line.7865"></a>
-<span class="sourceLineNo">7866</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7866"></a>
-<span class="sourceLineNo">7867</span>      lock(this.updatesLock.readLock());<a name="line.7867"></a>
-<span class="sourceLineNo">7868</span>      try {<a name="line.7868"></a>
-<span class="sourceLineNo">7869</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7869"></a>
-<span class="sourceLineNo">7870</span>        if (cpResult != null) {<a name="line.7870"></a>
-<span class="sourceLineNo">7871</span>          // Metrics updated below in the finally block.<a name="line.7871"></a>
-<span class="sourceLineNo">7872</span>          return returnResults? cpResult: null;<a name="line.7872"></a>
-<span class="sourceLineNo">7873</span>        }<a name="line.7873"></a>
-<span class="sourceLineNo">7874</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7874"></a>
-<span class="sourceLineNo">7875</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7875"></a>
-<span class="sourceLineNo">7876</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7876"></a>
-<span class="sourceLineNo">7877</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7877"></a>
-<span class="sourceLineNo">7878</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7878"></a>
-<span class="sourceLineNo">7879</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7879"></a>
-<span class="sourceLineNo">7880</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7880"></a>
-<span class="sourceLineNo">7881</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7881"></a>
-<span class="sourceLineNo">7882</span>        } else {<a name="line.7882"></a>
-<span class="sourceLineNo">7883</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7883"></a>
-<span class="sourceLineNo">7884</span>          // transaction.<a name="line.7884"></a>
-<span class="sourceLineNo">7885</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7885"></a>
-<span class="sourceLineNo">7886</span>          writeEntry = mvcc.begin();<a name="line.7886"></a>
-<span class="sourceLineNo">7887</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7887"></a>
-<span class="sourceLineNo">7888</span>        }<a name="line.7888"></a>
-<span class="sourceLineNo">7889</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7889"></a>
-<span class="sourceLineNo">7890</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7890"></a>
-<span class="sourceLineNo">7891</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7891"></a>
-<span class="sourceLineNo">7892</span>        }<a name="line.7892"></a>
-<span class="sourceLineNo">7893</span>        mvcc.completeAndWait(writeEntry);<a name="line.7893"></a>
-<span class="sourceLineNo">7894</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7894"></a>
-<span class="sourceLineNo">7895</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7895"></a>
-<span class="sourceLineNo">7896</span>            writeEntry.getWriteNumber());<a name="line.7896"></a>
-<span class="sourceLineNo">7897</span>        }<a name="line.7897"></a>
-<span class="sourceLineNo">7898</span>        writeEntry = null;<a name="line.7898"></a>
-<span class="sourceLineNo">7899</span>      } finally {<a name="line.7899"></a>
-<span class="sourceLineNo">7900</span>        this.updatesLock.readLock().unlock();<a name="line.7900"></a>
-<span class="sourceLineNo">7901</span>      }<a name="line.7901"></a>
-<span class="sourceLineNo">7902</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7902"></a>
-<span class="sourceLineNo">7903</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7903"></a>
-<span class="sourceLineNo">7904</span>    } finally {<a name="line.7904"></a>
-<span class="sourceLineNo">7905</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7905"></a>
-<span class="sourceLineNo">7906</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7906"></a>
-<span class="sourceLineNo">7907</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7907"></a>
-<span class="sourceLineNo">7908</span>      // a 0 increment.<a name="line.7908"></a>
-<span class="sourceLineNo">7909</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7909"></a>
-<span class="sourceLineNo">7910</span>      if (rowLock != null) {<a name="line.7910"></a>
-<span class="sourceLineNo">7911</span>        rowLock.release();<a name="line.7911"></a>
-<span class="sourceLineNo">7912</span>      }<a name="line.7912"></a>
-<span class="sourceLineNo">7913</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7913"></a>
-<span class="sourceLineNo">7914</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7914"></a>
-<span class="sourceLineNo">7915</span>      requestFlushIfNeeded();<a name="line.7915"></a>
-<span class="sourceLineNo">7916</span>      closeRegionOperation(op);<a name="line.7916"></a>
-<span class="sourceLineNo">7917</span>      if (this.metricsRegion != null) {<a name="line.7917"></a>
-<span class="sourceLineNo">7918</span>        switch (op) {<a name="line.7918"></a>
-<span class="sourceLineNo">7919</span>          case INCREMENT:<a name="line.7919"></a>
-<span class="sourceLineNo">7920</span>            this.metricsRegion.updateIncrement();<a name="line.7920"></a>
-<span class="sourceLineNo">7921</span>            break;<a name="line.7921"></a>
-<span class="sourceLineNo">7922</span>          case APPEND:<a name="line.7922"></a>
-<span class="sourceLineNo">7923</span>            this.metricsRegion.updateAppend();<a name="line.7923"></a>
+<span class="sourceLineNo">7849</span>   * &lt;p&gt;If increment, add deltas to current values or if an append, then<a name="line.7849"></a>
+<span class="sourceLineNo">7850</span>   * append the deltas to the current Cell values.<a name="line.7850"></a>
+<span class="sourceLineNo">7851</span>   *<a name="line.7851"></a>
+<span class="sourceLineNo">7852</span>   * &lt;p&gt;Append and Increment code paths are mostly the same. They differ in just a few places.<a name="line.7852"></a>
+<span class="sourceLineNo">7853</span>   * This method does the code path for increment and append and then in key spots, switches<a name="line.7853"></a>
+<span class="sourceLineNo">7854</span>   * on the passed in &lt;code&gt;op&lt;/code&gt; to do increment or append specific paths.<a name="line.7854"></a>
+<span class="sourceLineNo">7855</span>   */<a name="line.7855"></a>
+<span class="sourceLineNo">7856</span>  private Result doDelta(Operation op, Mutation mutation, long nonceGroup, long nonce,<a name="line.7856"></a>
+<span class="sourceLineNo">7857</span>      boolean returnResults) throws IOException {<a name="line.7857"></a>
+<span class="sourceLineNo">7858</span>    checkReadOnly();<a name="line.7858"></a>
+<span class="sourceLineNo">7859</span>    checkResources();<a name="line.7859"></a>
+<span class="sourceLineNo">7860</span>    checkRow(mutation.getRow(), op.toString());<a name="line.7860"></a>
+<span class="sourceLineNo">7861</span>    checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());<a name="line.7861"></a>
+<span class="sourceLineNo">7862</span>    this.writeRequestsCount.increment();<a name="line.7862"></a>
+<span class="sourceLineNo">7863</span>    WriteEntry writeEntry = null;<a name="line.7863"></a>
+<span class="sourceLineNo">7864</span>    startRegionOperation(op);<a name="line.7864"></a>
+<span class="sourceLineNo">7865</span>    List&lt;Cell&gt; results = returnResults? new ArrayList&lt;&gt;(mutation.size()): null;<a name="line.7865"></a>
+<span class="sourceLineNo">7866</span>    RowLock rowLock = null;<a name="line.7866"></a>
+<span class="sourceLineNo">7867</span>    MemStoreSizing memstoreAccounting = new NonThreadSafeMemStoreSizing();<a name="line.7867"></a>
+<span class="sourceLineNo">7868</span>    try {<a name="line.7868"></a>
+<span class="sourceLineNo">7869</span>      rowLock = getRowLockInternal(mutation.getRow(), false, null);<a name="line.7869"></a>
+<span class="sourceLineNo">7870</span>      lock(this.updatesLock.readLock());<a name="line.7870"></a>
+<span class="sourceLineNo">7871</span>      try {<a name="line.7871"></a>
+<span class="sourceLineNo">7872</span>        Result cpResult = doCoprocessorPreCall(op, mutation);<a name="line.7872"></a>
+<span class="sourceLineNo">7873</span>        if (cpResult != null) {<a name="line.7873"></a>
+<span class="sourceLineNo">7874</span>          // Metrics updated below in the finally block.<a name="line.7874"></a>
+<span class="sourceLineNo">7875</span>          return returnResults? cpResult: null;<a name="line.7875"></a>
+<span class="sourceLineNo">7876</span>        }<a name="line.7876"></a>
+<span class="sourceLineNo">7877</span>        Durability effectiveDurability = getEffectiveDurability(mutation.getDurability());<a name="line.7877"></a>
+<span class="sourceLineNo">7878</span>        Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore = new HashMap&lt;&gt;(mutation.getFamilyCellMap().size());<a name="line.7878"></a>
+<span class="sourceLineNo">7879</span>        // Reckon Cells to apply to WAL --  in returned walEdit -- and what to add to memstore and<a name="line.7879"></a>
+<span class="sourceLineNo">7880</span>        // what to return back to the client (in 'forMemStore' and 'results' respectively).<a name="line.7880"></a>
+<span class="sourceLineNo">7881</span>        WALEdit walEdit = reckonDeltas(op, mutation, effectiveDurability, forMemStore, results);<a name="line.7881"></a>
+<span class="sourceLineNo">7882</span>        // Actually write to WAL now if a walEdit to apply.<a name="line.7882"></a>
+<span class="sourceLineNo">7883</span>        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {<a name="line.7883"></a>
+<span class="sourceLineNo">7884</span>          writeEntry = doWALAppend(walEdit, effectiveDurability, nonceGroup, nonce);<a name="line.7884"></a>
+<span class="sourceLineNo">7885</span>        } else {<a name="line.7885"></a>
+<span class="sourceLineNo">7886</span>          // If walEdits is empty, it means we skipped the WAL; update LongAdders and start an mvcc<a name="line.7886"></a>
+<span class="sourceLineNo">7887</span>          // transaction.<a name="line.7887"></a>
+<span class="sourceLineNo">7888</span>          recordMutationWithoutWal(mutation.getFamilyCellMap());<a name="line.7888"></a>
+<span class="sourceLineNo">7889</span>          writeEntry = mvcc.begin();<a name="line.7889"></a>
+<span class="sourceLineNo">7890</span>          updateSequenceId(forMemStore.values(), writeEntry.getWriteNumber());<a name="line.7890"></a>
+<span class="sourceLineNo">7891</span>        }<a name="line.7891"></a>
+<span class="sourceLineNo">7892</span>        // Now write to MemStore. Do it a column family at a time.<a name="line.7892"></a>
+<span class="sourceLineNo">7893</span>        for (Map.Entry&lt;HStore, List&lt;Cell&gt;&gt; e : forMemStore.entrySet()) {<a name="line.7893"></a>
+<span class="sourceLineNo">7894</span>          applyToMemStore(e.getKey(), e.getValue(), true, memstoreAccounting);<a name="line.7894"></a>
+<span class="sourceLineNo">7895</span>        }<a name="line.7895"></a>
+<span class="sourceLineNo">7896</span>        mvcc.completeAndWait(writeEntry);<a name="line.7896"></a>
+<span class="sourceLineNo">7897</span>        if (rsServices != null &amp;&amp; rsServices.getNonceManager() != null) {<a name="line.7897"></a>
+<span class="sourceLineNo">7898</span>          rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,<a name="line.7898"></a>
+<span class="sourceLineNo">7899</span>            writeEntry.getWriteNumber());<a name="line.7899"></a>
+<span class="sourceLineNo">7900</span>        }<a name="line.7900"></a>
+<span class="sourceLineNo">7901</span>        writeEntry = null;<a name="line.7901"></a>
+<span class="sourceLineNo">7902</span>      } finally {<a name="line.7902"></a>
+<span class="sourceLineNo">7903</span>        this.updatesLock.readLock().unlock();<a name="line.7903"></a>
+<span class="sourceLineNo">7904</span>      }<a name="line.7904"></a>
+<span class="sourceLineNo">7905</span>      // If results is null, then client asked that we not return the calculated results.<a name="line.7905"></a>
+<span class="sourceLineNo">7906</span>      return results != null &amp;&amp; returnResults? Result.create(results): Result.EMPTY_RESULT;<a name="line.7906"></a>
+<span class="sourceLineNo">7907</span>    } finally {<a name="line.7907"></a>
+<span class="sourceLineNo">7908</span>      // Call complete always, even on success. doDelta is doing a Get READ_UNCOMMITTED when it goes<a name="line.7908"></a>
+<span class="sourceLineNo">7909</span>      // to get current value under an exclusive lock so no need so no need to wait to return to<a name="line.7909"></a>
+<span class="sourceLineNo">7910</span>      // the client. Means only way to read-your-own-increment or append is to come in with an<a name="line.7910"></a>
+<span class="sourceLineNo">7911</span>      // a 0 increment.<a name="line.7911"></a>
+<span class="sourceLineNo">7912</span>      if (writeEntry != null) mvcc.complete(writeEntry);<a name="line.7912"></a>
+<span class="sourceLineNo">7913</span>      if (rowLock != null) {<a name="line.7913"></a>
+<span class="sourceLineNo">7914</span>        rowLock.release();<a name="line.7914"></a>
+<span class="sourceLineNo">7915</span>      }<a name="line.7915"></a>
+<span class="sourceLineNo">7916</span>      // Request a cache flush if over the limit.  Do it outside update lock.<a name="line.7916"></a>
+<span class="sourceLineNo">7917</span>      incMemStoreSize(memstoreAccounting.getMemStoreSize());<a name="line.7917"></a>
+<span class="sourceLineNo">7918</span>      requestFlushIfNeeded();<a name="line.7918"></a>
+<span class="sourceLineNo">7919</span>      closeRegionOperation(op);<a name="line.7919"></a>
+<span class="sourceLineNo">7920</span>      if (this.metricsRegion != null) {<a name="line.7920"></a>
+<span class="sourceLineNo">7921</span>        switch (op) {<a name="line.7921"></a>
+<span class="sourceLineNo">7922</span>          case INCREMENT:<a name="line.7922"></a>
+<span class="sourceLineNo">7923</span>            this.metricsRegion.updateIncrement();<a name="line.7923"></a>
 <span class="sourceLineNo">7924</span>            break;<a name="line.7924"></a>
-<span class="sourceLineNo">7925</span>          default:<a name="line.7925"></a>
-<span class="sourceLineNo">7926</span>            break;<a name="line.7926"></a>
-<span class="sourceLineNo">7927</span>        }<a name="line.7927"></a>
-<span class="sourceLineNo">7928</span>      }<a name="line.7928"></a>
-<span class="sourceLineNo">7929</span>    }<a name="line.7929"></a>
-<span class="sourceLineNo">7930</span>  }<a name="line.7930"></a>
-<span class="sourceLineNo">7931</span><a name="line.7931"></a>
-<span class="sourceLineNo">7932</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7932"></a>
-<span class="sourceLineNo">7933</span>      long nonce)<a name="line.7933"></a>
-<span class="sourceLineNo">7934</span>  throws IOException {<a name="line.7934"></a>
-<span class="sourceLineNo">7935</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7935"></a>
-<span class="sourceLineNo">7936</span>      nonceGroup, nonce);<a name="line.7936"></a>
-<span class="sourceLineNo">7937</span>  }<a name="line.7937"></a>
-<span class="sourceLineNo">7938</span><a name="line.7938"></a>
-<span class="sourceLineNo">7939</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7939"></a>
-<span class="sourceLineNo">7940</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7940"></a>
-<span class="sourceLineNo">7941</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7941"></a>
-<span class="sourceLineNo">7942</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7942"></a>
-<span class="sourceLineNo">7943</span>  }<a name="line.7943"></a>
-<span class="sourceLineNo">7944</span><a name="line.7944"></a>
-<span class="sourceLineNo">7945</span>  /**<a name="line.7945"></a>
-<span class="sourceLineNo">7946</span>   * @return writeEntry associated with this append<a name="line.7946"></a>
-<span class="sourceLineNo">7947</span>   */<a name="line.7947"></a>
-<span class="sourceLineNo">7948</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7948"></a>
-<span class="sourceLineNo">7949</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7949"></a>
-<span class="sourceLineNo">7950</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7950"></a>
-<span class="sourceLineNo">7951</span>        "WALEdit is null or empty!");<a name="line.7951"></a>
-<span class="sourceLineNo">7952</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7952"></a>
-<span class="sourceLineNo">7953</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7953"></a>
-<span class="sourceLineNo">7954</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7954"></a>
-<span class="sourceLineNo">7955</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7955"></a>
-<span class="sourceLineNo">7956</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7956"></a>
-<span class="sourceLineNo">7957</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7957"></a>
-<span class="sourceLineNo">7958</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7958"></a>
-<span class="sourceLineNo">7959</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7959"></a>
-<span class="sourceLineNo">7960</span>            nonceGroup, nonce, mvcc) :<a name="line.7960"></a>
+<span class="sourceLineNo">7925</span>          case APPEND:<a name="line.7925"></a>
+<span class="sourceLineNo">7926</span>            this.metricsRegion.updateAppend();<a name="line.7926"></a>
+<span class="sourceLineNo">7927</span>            break;<a name="line.7927"></a>
+<span class="sourceLineNo">7928</span>          default:<a name="line.7928"></a>
+<span class="sourceLineNo">7929</span>            break;<a name="line.7929"></a>
+<span class="sourceLineNo">7930</span>        }<a name="line.7930"></a>
+<span class="sourceLineNo">7931</span>      }<a name="line.7931"></a>
+<span class="sourceLineNo">7932</span>    }<a name="line.7932"></a>
+<span class="sourceLineNo">7933</span>  }<a name="line.7933"></a>
+<span class="sourceLineNo">7934</span><a name="line.7934"></a>
+<span class="sourceLineNo">7935</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, long nonceGroup,<a name="line.7935"></a>
+<span class="sourceLineNo">7936</span>      long nonce)<a name="line.7936"></a>
+<span class="sourceLineNo">7937</span>  throws IOException {<a name="line.7937"></a>
+<span class="sourceLineNo">7938</span>    return doWALAppend(walEdit, durability, WALKey.EMPTY_UUIDS, System.currentTimeMillis(),<a name="line.7938"></a>
+<span class="sourceLineNo">7939</span>      nonceGroup, nonce);<a name="line.7939"></a>
+<span class="sourceLineNo">7940</span>  }<a name="line.7940"></a>
+<span class="sourceLineNo">7941</span><a name="line.7941"></a>
+<span class="sourceLineNo">7942</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7942"></a>
+<span class="sourceLineNo">7943</span>      long now, long nonceGroup, long nonce) throws IOException {<a name="line.7943"></a>
+<span class="sourceLineNo">7944</span>    return doWALAppend(walEdit, durability, clusterIds, now, nonceGroup, nonce,<a name="line.7944"></a>
+<span class="sourceLineNo">7945</span>        SequenceId.NO_SEQUENCE_ID);<a name="line.7945"></a>
+<span class="sourceLineNo">7946</span>  }<a name="line.7946"></a>
+<span class="sourceLineNo">7947</span><a name="line.7947"></a>
+<span class="sourceLineNo">7948</span>  /**<a name="line.7948"></a>
+<span class="sourceLineNo">7949</span>   * @return writeEntry associated with this append<a name="line.7949"></a>
+<span class="sourceLineNo">7950</span>   */<a name="line.7950"></a>
+<span class="sourceLineNo">7951</span>  private WriteEntry doWALAppend(WALEdit walEdit, Durability durability, List&lt;UUID&gt; clusterIds,<a name="line.7951"></a>
+<span class="sourceLineNo">7952</span>      long now, long nonceGroup, long nonce, long origLogSeqNum) throws IOException {<a name="line.7952"></a>
+<span class="sourceLineNo">7953</span>    Preconditions.checkArgument(walEdit != null &amp;&amp; !walEdit.isEmpty(),<a name="line.7953"></a>
+<span class="sourceLineNo">7954</span>        "WALEdit is null or empty!");<a name="line.7954"></a>
+<span class="sourceLineNo">7955</span>    Preconditions.checkArgument(!walEdit.isReplay() || origLogSeqNum != SequenceId.NO_SEQUENCE_ID,<a name="line.7955"></a>
+<span class="sourceLineNo">7956</span>        "Invalid replay sequence Id for replay WALEdit!");<a name="line.7956"></a>
+<span class="sourceLineNo">7957</span>    // Using default cluster id, as this can only happen in the originating cluster.<a name="line.7957"></a>
+<span class="sourceLineNo">7958</span>    // A slave cluster receives the final value (not the delta) as a Put. We use HLogKey<a name="line.7958"></a>
+<span class="sourceLineNo">7959</span>    // here instead of WALKeyImpl directly to support legacy coprocessors.<a name="line.7959"></a>
+<span class="sourceLineNo">7960</span>    WALKeyImpl walKey = walEdit.isReplay()?<a name="line.7960"></a>
 <span class="sourceLineNo">7961</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7961"></a>
-<span class="sourceLineNo">7962</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
-<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7963"></a>
-<span class="sourceLineNo">7964</span>    if (walEdit.isReplay()) {<a name="line.7964"></a>
-<span class="sourceLineNo">7965</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7965"></a>
-<span class="sourceLineNo">7966</span>    }<a name="line.7966"></a>
-<span class="sourceLineNo">7967</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7967"></a>
-<span class="sourceLineNo">7968</span>    //system lifecycle events like flushes or compactions<a name="line.7968"></a>
-<span class="sourceLineNo">7969</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7969"></a>
-<span class="sourceLineNo">7970</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7970"></a>
-<span class="sourceLineNo">7971</span>    }<a name="line.7971"></a>
-<span class="sourceLineNo">7972</span>    WriteEntry writeEntry = null;<a name="line.7972"></a>
-<span class="sourceLineNo">7973</span>    try {<a name="line.7973"></a>
-<span class="sourceLineNo">7974</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7974"></a>
-<span class="sourceLineNo">7975</span>      // Call sync on our edit.<a name="line.7975"></a>
-<span class="sourceLineNo">7976</span>      if (txid != 0) {<a name="line.7976"></a>
-<span class="sourceLineNo">7977</span>        sync(txid, durability);<a name="line.7977"></a>
-<span class="sourceLineNo">7978</span>      }<a name="line.7978"></a>
-<span class="sourceLineNo">7979</span>      writeEntry = walKey.getWriteEntry();<a name="line.7979"></a>
-<span class="sourceLineNo">7980</span>    } catch (IOException ioe) {<a name="line.7980"></a>
-<span class="sourceLineNo">7981</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7981"></a>
-<span class="sourceLineNo">7982</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7982"></a>
-<span class="sourceLineNo">7983</span>      }<a name="line.7983"></a>
-<span class="sourceLineNo">7984</span>      throw ioe;<a name="line.7984"></a>
-<span class="sourceLineNo">7985</span>    }<a name="line.7985"></a>
-<span class="sourceLineNo">7986</span>    return writeEntry;<a name="line.7986"></a>
-<span class="sourceLineNo">7987</span>  }<a name="line.7987"></a>
-<span class="sourceLineNo">7988</span><a name="line.7988"></a>
-<span class="sourceLineNo">7989</span>  /**<a name="line.7989"></a>
-<span class="sourceLineNo">7990</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7990"></a>
-<span class="sourceLineNo">7991</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7991"></a>
-<span class="sourceLineNo">7992</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7992"></a>
-<span class="sourceLineNo">7993</span>   */<a name="line.7993"></a>
-<span class="sourceLineNo">7994</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7994"></a>
-<span class="sourceLineNo">7995</span>  throws IOException {<a name="line.7995"></a>
-<span class="sourceLineNo">7996</span>    Result result = null;<a name="line.7996"></a>
-<span class="sourceLineNo">7997</span>    if (this.coprocessorHost != null) {<a name="line.7997"></a>
-<span class="sourceLineNo">7998</span>      switch(op) {<a name="line.7998"></a>
-<span class="sourceLineNo">7999</span>        case INCREMENT:<a name="line.7999"></a>
-<span class="sourceLineNo">8000</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8000"></a>
-<span class="sourceLineNo">8001</span>          break;<a name="line.8001"></a>
-<span class="sourceLineNo">8002</span>        case APPEND:<a name="line.8002"></a>
-<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8003"></a>
+<span class="sourceLineNo">7962</span>          this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7962"></a>
+<span class="sourceLineNo">7963</span>            nonceGroup, nonce, mvcc) :<a name="line.7963"></a>
+<span class="sourceLineNo">7964</span>        new WALKeyImpl(this.getRegionInfo().getEncodedNameAsBytes(),<a name="line.7964"></a>
+<span class="sourceLineNo">7965</span>            this.htableDescriptor.getTableName(), SequenceId.NO_SEQUENCE_ID, now, clusterIds,<a name="line.7965"></a>
+<span class="sourceLineNo">7966</span>            nonceGroup, nonce, mvcc, this.getReplicationScope());<a name="line.7966"></a>
+<span class="sourceLineNo">7967</span>    if (walEdit.isReplay()) {<a name="line.7967"></a>
+<span class="sourceLineNo">7968</span>      walKey.setOrigLogSeqNum(origLogSeqNum);<a name="line.7968"></a>
+<span class="sourceLineNo">7969</span>    }<a name="line.7969"></a>
+<span class="sourceLineNo">7970</span>    //don't call the coproc hook for writes to the WAL caused by<a name="line.7970"></a>
+<span class="sourceLineNo">7971</span>    //system lifecycle events like flushes or compactions<a name="line.7971"></a>
+<span class="sourceLineNo">7972</span>    if (this.coprocessorHost != null &amp;&amp; !walEdit.isMetaEdit()) {<a name="line.7972"></a>
+<span class="sourceLineNo">7973</span>      this.coprocessorHost.preWALAppend(walKey, walEdit);<a name="line.7973"></a>
+<span class="sourceLineNo">7974</span>    }<a name="line.7974"></a>
+<span class="sourceLineNo">7975</span>    WriteEntry writeEntry = null;<a name="line.7975"></a>
+<span class="sourceLineNo">7976</span>    try {<a name="line.7976"></a>
+<span class="sourceLineNo">7977</span>      long txid = this.wal.append(this.getRegionInfo(), walKey, walEdit, true);<a name="line.7977"></a>
+<span class="sourceLineNo">7978</span>      // Call sync on our edit.<a name="line.7978"></a>
+<span class="sourceLineNo">7979</span>      if (txid != 0) {<a name="line.7979"></a>
+<span class="sourceLineNo">7980</span>        sync(txid, durability);<a name="line.7980"></a>
+<span class="sourceLineNo">7981</span>      }<a name="line.7981"></a>
+<span class="sourceLineNo">7982</span>      writeEntry = walKey.getWriteEntry();<a name="line.7982"></a>
+<span class="sourceLineNo">7983</span>    } catch (IOException ioe) {<a name="line.7983"></a>
+<span class="sourceLineNo">7984</span>      if (walKey != null &amp;&amp; walKey.getWriteEntry() != null) {<a name="line.7984"></a>
+<span class="sourceLineNo">7985</span>        mvcc.complete(walKey.getWriteEntry());<a name="line.7985"></a>
+<span class="sourceLineNo">7986</span>      }<a name="line.7986"></a>
+<span class="sourceLineNo">7987</span>      throw ioe;<a name="line.7987"></a>
+<span class="sourceLineNo">7988</span>    }<a name="line.7988"></a>
+<span class="sourceLineNo">7989</span>    return writeEntry;<a name="line.7989"></a>
+<span class="sourceLineNo">7990</span>  }<a name="line.7990"></a>
+<span class="sourceLineNo">7991</span><a name="line.7991"></a>
+<span class="sourceLineNo">7992</span>  /**<a name="line.7992"></a>
+<span class="sourceLineNo">7993</span>   * Do coprocessor pre-increment or pre-append call.<a name="line.7993"></a>
+<span class="sourceLineNo">7994</span>   * @return Result returned out of the coprocessor, which means bypass all further processing and<a name="line.7994"></a>
+<span class="sourceLineNo">7995</span>   *  return the proffered Result instead, or null which means proceed.<a name="line.7995"></a>
+<span class="sourceLineNo">7996</span>   */<a name="line.7996"></a>
+<span class="sourceLineNo">7997</span>  private Result doCoprocessorPreCall(final Operation op, final Mutation mutation)<a name="line.7997"></a>
+<span class="sourceLineNo">7998</span>  throws IOException {<a name="line.7998"></a>
+<span class="sourceLineNo">7999</span>    Result result = null;<a name="line.7999"></a>
+<span class="sourceLineNo">8000</span>    if (this.coprocessorHost != null) {<a name="line.8000"></a>
+<span class="sourceLineNo">8001</span>      switch(op) {<a name="line.8001"></a>
+<span class="sourceLineNo">8002</span>        case INCREMENT:<a name="line.8002"></a>
+<span class="sourceLineNo">8003</span>          result = this.coprocessorHost.preIncrementAfterRowLock((Increment)mutation);<a name="line.8003"></a>
 <span class="sourceLineNo">8004</span>          break;<a name="line.8004"></a>
-<span class="sourceLineNo">8005</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8005"></a>
-<span class="sourceLineNo">8006</span>      }<a name="line.8006"></a>
-<span class="sourceLineNo">8007</span>    }<a name="line.8007"></a>
-<span class="sourceLineNo">8008</span>    return result;<a name="line.8008"></a>
-<span class="sourceLineNo">8009</span>  }<a name="line.8009"></a>
-<span class="sourceLineNo">8010</span><a name="line.8010"></a>
-<span class="sourceLineNo">8011</span>  /**<a name="line.8011"></a>
-<span class="sourceLineNo">8012</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8012"></a>
-<span class="sourceLineNo">8013</span>   * always the same dependent on whether to write WAL.<a name="line.8013"></a>
-<span class="sourceLineNo">8014</span>   *<a name="line.8014"></a>
-<span class="sourceLineNo">8015</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8015"></a>
-<span class="sourceLineNo">8016</span>   *  doesn't want results).<a name="line.8016"></a>
-<span class="sourceLineNo">8017</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8017"></a>
-<span class="sourceLineNo">8018</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8018"></a>
-<span class="sourceLineNo">8019</span>   */<a name="line.8019"></a>
-<span class="sourceLineNo">8020</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8020"></a>
-<span class="sourceLineNo">8021</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8021"></a>
-<span class="sourceLineNo">8022</span>    WALEdit walEdit = null;<a name="line.8022"></a>
-<span class="sourceLineNo">8023</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8023"></a>
-<span class="sourceLineNo">8024</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8024"></a>
-<span class="sourceLineNo">8025</span>    // Process a Store/family at a time.<a name="line.8025"></a>
-<span class="sourceLineNo">8026</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8026"></a>
-<span class="sourceLineNo">8027</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8027"></a>
-<span class="sourceLineNo">8028</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8028"></a>
-<span class="sourceLineNo">8029</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8029"></a>
-<span class="sourceLineNo">8030</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8030"></a>
-<span class="sourceLineNo">8031</span>        effectiveDurability, now, deltas, results);<a name="line.8031"></a>
-<span class="sourceLineNo">8032</span>      if (!toApply.isEmpty()) {<a name="line.8032"></a>
-<span class="sourceLineNo">8033</span>        for (Cell cell : toApply) {<a name="line.8033"></a>
-<span class="sourceLineNo">8034</span>          HStore store = getStore(cell);<a name="line.8034"></a>
-<span class="sourceLineNo">8035</span>          if (store == null) {<a name="line.8035"></a>
-<span class="sourceLineNo">8036</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8036"></a>
-<span class="sourceLineNo">8037</span>          } else {<a name="line.8037"></a>
-<span class="sourceLineNo">8038</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8038"></a>
-<span class="sourceLineNo">8039</span>          }<a name="line.8039"></a>
-<span class="sourceLineNo">8040</span>        }<a name="line.8040"></a>
-<span class="sourceLineNo">8041</span>        if (writeToWAL) {<a name="line.8041"></a>
-<span class="sourceLineNo">8042</span>          if (walEdit == null) {<a name="line.8042"></a>
-<span class="sourceLineNo">8043</span>            walEdit = new WALEdit();<a name="line.8043"></a>
-<span class="sourceLineNo">8044</span>          }<a name="line.8044"></a>
-<span class="sourceLineNo">8045</span>          walEdit.getCells().addAll(toApply);<a name="line.8045"></a>
-<span class="sourceLineNo">8046</span>        }<a name="line.8046"></a>
-<span class="sourceLineNo">8047</span>      }<a name="line.8047"></a>
-<span class="sourceLineNo">8048</span>    }<a name="line.8048"></a>
-<span class="sourceLineNo">8049</span>    return walEdit;<a name="line.8049"></a>
-<span class="sourceLineNo">8050</span>  }<a name="line.8050"></a>
-<span class="sourceLineNo">8051</span><a name="line.8051"></a>
-<span class="sourceLineNo">8052</span>  /**<a name="line.8052"></a>
-<span class="sourceLineNo">8053</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8053"></a>
-<span class="sourceLineNo">8054</span>   * column family/Store.<a name="line.8054"></a>
-<span class="sourceLineNo">8055</span>   *<a name="line.8055"></a>
-<span class="sourceLineNo">8056</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8056"></a>
-<span class="sourceLineNo">8057</span>   *<a name="line.8057"></a>
-<span class="sourceLineNo">8058</span>   * @param op Whether Increment or Append<a name="line.8058"></a>
-<span class="sourceLineNo">8059</span>   * @param mutation The encompassing Mutation object<a name="line.8059"></a>
-<span class="sourceLineNo">8060</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8060"></a>
-<span class="sourceLineNo">8061</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8061"></a>
-<span class="sourceLineNo">8062</span>   *                client doesn't want results returned.<a name="line.8062"></a>
-<span class="sourceLineNo">8063</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8063"></a>
-<span class="sourceLineNo">8064</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8064"></a>
-<span class="sourceLineNo">8065</span>   */<a name="line.8065"></a>
-<span class="sourceLineNo">8066</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8066"></a>
-<span class="sourceLineNo">8067</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8067"></a>
-<span class="sourceLineNo">8068</span>      throws IOException {<a name="line.8068"></a>
-<span class="sourceLineNo">8069</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8069"></a>
-<span class="sourceLineNo">8070</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8070"></a>
-<span class="sourceLineNo">8071</span>    // Get previous values for all columns in this family.<a name="line.8071"></a>
-<span class="sourceLineNo">8072</span>    TimeRange tr = null;<a name="line.8072"></a>
-<span class="sourceLineNo">8073</span>    switch (op) {<a name="line.8073"></a>
-<span class="sourceLineNo">8074</span>      case INCREMENT:<a name="line.8074"></a>
-<span class="sourceLineNo">8075</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8075"></a>
-<span class="sourceLineNo">8076</span>        break;<a name="line.8076"></a>
-<span class="sourceLineNo">8077</span>      case APPEND:<a name="line.8077"></a>
-<span class="sourceLineNo">8078</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8078"></a>
+<span class="sourceLineNo">8005</span>        case APPEND:<a name="line.8005"></a>
+<span class="sourceLineNo">8006</span>          result = this.coprocessorHost.preAppendAfterRowLock((Append)mutation);<a name="line.8006"></a>
+<span class="sourceLineNo">8007</span>          break;<a name="line.8007"></a>
+<span class="sourceLineNo">8008</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8008"></a>
+<span class="sourceLineNo">8009</span>      }<a name="line.8009"></a>
+<span class="sourceLineNo">8010</span>    }<a name="line.8010"></a>
+<span class="sourceLineNo">8011</span>    return result;<a name="line.8011"></a>
+<span class="sourceLineNo">8012</span>  }<a name="line.8012"></a>
+<span class="sourceLineNo">8013</span><a name="line.8013"></a>
+<span class="sourceLineNo">8014</span>  /**<a name="line.8014"></a>
+<span class="sourceLineNo">8015</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client; these Sets are not<a name="line.8015"></a>
+<span class="sourceLineNo">8016</span>   * always the same dependent on whether to write WAL.<a name="line.8016"></a>
+<span class="sourceLineNo">8017</span>   *<a name="line.8017"></a>
+<span class="sourceLineNo">8018</span>   * @param results Fill in here what goes back to the Client if it is non-null (if null, client<a name="line.8018"></a>
+<span class="sourceLineNo">8019</span>   *  doesn't want results).<a name="line.8019"></a>
+<span class="sourceLineNo">8020</span>   * @param forMemStore Fill in here what to apply to the MemStore (by Store).<a name="line.8020"></a>
+<span class="sourceLineNo">8021</span>   * @return A WALEdit to apply to WAL or null if we are to skip the WAL.<a name="line.8021"></a>
+<span class="sourceLineNo">8022</span>   */<a name="line.8022"></a>
+<span class="sourceLineNo">8023</span>  private WALEdit reckonDeltas(Operation op, Mutation mutation, Durability effectiveDurability,<a name="line.8023"></a>
+<span class="sourceLineNo">8024</span>      Map&lt;HStore, List&lt;Cell&gt;&gt; forMemStore, List&lt;Cell&gt; results) throws IOException {<a name="line.8024"></a>
+<span class="sourceLineNo">8025</span>    WALEdit walEdit = null;<a name="line.8025"></a>
+<span class="sourceLineNo">8026</span>    long now = EnvironmentEdgeManager.currentTime();<a name="line.8026"></a>
+<span class="sourceLineNo">8027</span>    final boolean writeToWAL = effectiveDurability != Durability.SKIP_WAL;<a name="line.8027"></a>
+<span class="sourceLineNo">8028</span>    // Process a Store/family at a time.<a name="line.8028"></a>
+<span class="sourceLineNo">8029</span>    for (Map.Entry&lt;byte [], List&lt;Cell&gt;&gt; entry: mutation.getFamilyCellMap().entrySet()) {<a name="line.8029"></a>
+<span class="sourceLineNo">8030</span>      final byte[] columnFamilyName = entry.getKey();<a name="line.8030"></a>
+<span class="sourceLineNo">8031</span>      List&lt;Cell&gt; deltas = entry.getValue();<a name="line.8031"></a>
+<span class="sourceLineNo">8032</span>      // Reckon for the Store what to apply to WAL and MemStore.<a name="line.8032"></a>
+<span class="sourceLineNo">8033</span>      List&lt;Cell&gt; toApply = reckonDeltasByStore(stores.get(columnFamilyName), op, mutation,<a name="line.8033"></a>
+<span class="sourceLineNo">8034</span>        effectiveDurability, now, deltas, results);<a name="line.8034"></a>
+<span class="sourceLineNo">8035</span>      if (!toApply.isEmpty()) {<a name="line.8035"></a>
+<span class="sourceLineNo">8036</span>        for (Cell cell : toApply) {<a name="line.8036"></a>
+<span class="sourceLineNo">8037</span>          HStore store = getStore(cell);<a name="line.8037"></a>
+<span class="sourceLineNo">8038</span>          if (store == null) {<a name="line.8038"></a>
+<span class="sourceLineNo">8039</span>            checkFamily(CellUtil.cloneFamily(cell));<a name="line.8039"></a>
+<span class="sourceLineNo">8040</span>          } else {<a name="line.8040"></a>
+<span class="sourceLineNo">8041</span>            forMemStore.computeIfAbsent(store, key -&gt; new ArrayList&lt;&gt;()).add(cell);<a name="line.8041"></a>
+<span class="sourceLineNo">8042</span>          }<a name="line.8042"></a>
+<span class="sourceLineNo">8043</span>        }<a name="line.8043"></a>
+<span class="sourceLineNo">8044</span>        if (writeToWAL) {<a name="line.8044"></a>
+<span class="sourceLineNo">8045</span>          if (walEdit == null) {<a name="line.8045"></a>
+<span class="sourceLineNo">8046</span>            walEdit = new WALEdit();<a name="line.8046"></a>
+<span class="sourceLineNo">8047</span>          }<a name="line.8047"></a>
+<span class="sourceLineNo">8048</span>          walEdit.getCells().addAll(toApply);<a name="line.8048"></a>
+<span class="sourceLineNo">8049</span>        }<a name="line.8049"></a>
+<span class="sourceLineNo">8050</span>      }<a name="line.8050"></a>
+<span class="sourceLineNo">8051</span>    }<a name="line.8051"></a>
+<span class="sourceLineNo">8052</span>    return walEdit;<a name="line.8052"></a>
+<span class="sourceLineNo">8053</span>  }<a name="line.8053"></a>
+<span class="sourceLineNo">8054</span><a name="line.8054"></a>
+<span class="sourceLineNo">8055</span>  /**<a name="line.8055"></a>
+<span class="sourceLineNo">8056</span>   * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed<a name="line.8056"></a>
+<span class="sourceLineNo">8057</span>   * column family/Store.<a name="line.8057"></a>
+<span class="sourceLineNo">8058</span>   *<a name="line.8058"></a>
+<span class="sourceLineNo">8059</span>   * Does Get of current value and then adds passed in deltas for this Store returning the result.<a name="line.8059"></a>
+<span class="sourceLineNo">8060</span>   *<a name="line.8060"></a>
+<span class="sourceLineNo">8061</span>   * @param op Whether Increment or Append<a name="line.8061"></a>
+<span class="sourceLineNo">8062</span>   * @param mutation The encompassing Mutation object<a name="line.8062"></a>
+<span class="sourceLineNo">8063</span>   * @param deltas Changes to apply to this Store; either increment amount or data to append<a name="line.8063"></a>
+<span class="sourceLineNo">8064</span>   * @param results In here we accumulate all the Cells we are to return to the client. If null,<a name="line.8064"></a>
+<span class="sourceLineNo">8065</span>   *                client doesn't want results returned.<a name="line.8065"></a>
+<span class="sourceLineNo">8066</span>   * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current<a name="line.8066"></a>
+<span class="sourceLineNo">8067</span>   *  values. Side effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.<a name="line.8067"></a>
+<span class="sourceLineNo">8068</span>   */<a name="line.8068"></a>
+<span class="sourceLineNo">8069</span>  private List&lt;Cell&gt; reckonDeltasByStore(HStore store, Operation op, Mutation mutation,<a name="line.8069"></a>
+<span class="sourceLineNo">8070</span>      Durability effectiveDurability, long now, List&lt;Cell&gt; deltas, List&lt;Cell&gt; results)<a name="line.8070"></a>
+<span class="sourceLineNo">8071</span>      throws IOException {<a name="line.8071"></a>
+<span class="sourceLineNo">8072</span>    byte[] columnFamily = store.getColumnFamilyDescriptor().getName();<a name="line.8072"></a>
+<span class="sourceLineNo">8073</span>    List&lt;Pair&lt;Cell, Cell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());<a name="line.8073"></a>
+<span class="sourceLineNo">8074</span>    // Get previous values for all columns in this family.<a name="line.8074"></a>
+<span class="sourceLineNo">8075</span>    TimeRange tr = null;<a name="line.8075"></a>
+<span class="sourceLineNo">8076</span>    switch (op) {<a name="line.8076"></a>
+<span class="sourceLineNo">8077</span>      case INCREMENT:<a name="line.8077"></a>
+<span class="sourceLineNo">8078</span>        tr = ((Increment)mutation).getTimeRange();<a name="line.8078"></a>
 <span class="sourceLineNo">8079</span>        break;<a name="line.8079"></a>
-<span class="sourceLineNo">8080</span>      default:<a name="line.8080"></a>
-<span class="sourceLineNo">8081</span>        break;<a name="line.8081"></a>
-<span class="sourceLineNo">8082</span>    }<a name="line.8082"></a>
-<span class="sourceLineNo">8083</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8083"></a>
-<span class="sourceLineNo">8084</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8084"></a>
-<span class="sourceLineNo">8085</span>    // add new column initialized to the delta amount<a name="line.8085"></a>
-<span class="sourceLineNo">8086</span>    int currentValuesIndex = 0;<a name="line.8086"></a>
-<span class="sourceLineNo">8087</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8087"></a>
-<span class="sourceLineNo">8088</span>      Cell delta = deltas.get(i);<a name="line.8088"></a>
-<span class="sourceLineNo">8089</span>      Cell currentValue = null;<a name="line.8089"></a>
-<span class="sourceLineNo">8090</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8090"></a>
-<span class="sourceLineNo">8091</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8091"></a>
-<span class="sourceLineNo">8092</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8092"></a>
-<span class="sourceLineNo">8093</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8093"></a>
-<span class="sourceLineNo">8094</span>          currentValuesIndex++;<a name="line.8094"></a>
-<span class="sourceLineNo">8095</span>        }<a name="line.8095"></a>
-<span class="sourceLineNo">8096</span>      }<a name="line.8096"></a>
-<span class="sourceLineNo">8097</span><a name="line.8097"></a>
-<span class="sourceLineNo">8098</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8098"></a>
-<span class="sourceLineNo">8099</span>      Cell newCell = null;<a name="line.8099"></a>
-<span class="sourceLineNo">8100</span>      switch (op) {<a name="line.8100"></a>
-<span class="sourceLineNo">8101</span>        case INCREMENT:<a name="line.8101"></a>
-<span class="sourceLineNo">8102</span>          long deltaAmount = getLongValue(delta);<a name="line.8102"></a>
-<span class="sourceLineNo">8103</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8103"></a>
-<span class="sourceLineNo">8104</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8104"></a>
-<span class="sourceLineNo">8105</span>          break;<a name="line.8105"></a>
-<span class="sourceLineNo">8106</span>        case APPEND:<a name="line.8106"></a>
-<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8107"></a>
-<span class="sourceLineNo">8108</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8108"></a>
-<span class="sourceLineNo">8109</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8109"></a>
-<span class="sourceLineNo">8110</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8110"></a>
-<span class="sourceLineNo">8111</span>                    .array()<a name="line.8111"></a>
-<span class="sourceLineNo">8112</span>          );<a name="line.8112"></a>
-<span class="sourceLineNo">8113</span>          break;<a name="line.8113"></a>
-<span class="sourceLineNo">8114</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8114"></a>
-<span class="sourceLineNo">8115</span>      }<a name="line.8115"></a>
-<span class="sourceLineNo">8116</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8116"></a>
-<span class="sourceLineNo">8117</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8117"></a>
-<span class="sourceLineNo">8118</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8118"></a>
-<span class="sourceLineNo">8119</span>            this.maxCellSize + " bytes";<a name="line.8119"></a>
-<span class="sourceLineNo">8120</span>        if (LOG.isDebugEnabled()) {<a name="line.8120"></a>
-<span class="sourceLineNo">8121</span>          LOG.debug(msg);<a name="line.8121"></a>
-<span class="sourceLineNo">8122</span>        }<a name="line.8122"></a>
-<span class="sourceLineNo">8123</span>        throw new DoNotRetryIOException(msg);<a name="line.8123"></a>
-<span class="sourceLineNo">8124</span>      }<a name="line.8124"></a>
-<span class="sourceLineNo">8125</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8125"></a>
-<span class="sourceLineNo">8126</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8126"></a>
-<span class="sourceLineNo">8127</span>      if (results != null) {<a name="line.8127"></a>
-<span class="sourceLineNo">8128</span>        results.add(newCell);<a name="line.8128"></a>
-<span class="sourceLineNo">8129</span>      }<a name="line.8129"></a>
-<span class="sourceLineNo">8130</span>    }<a name="line.8130"></a>
-<span class="sourceLineNo">8131</span><a name="line.8131"></a>
-<span class="sourceLineNo">8132</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8132"></a>
-<span class="sourceLineNo">8133</span>    if (coprocessorHost != null) {<a name="line.8133"></a>
-<span class="sourceLineNo">8134</span>      // Here the operation must be increment or append.<a name="line.8134"></a>
-<span class="sourceLineNo">8135</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8135"></a>
-<span class="sourceLineNo">8136</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8136"></a>
-<span class="sourceLineNo">8137</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8137"></a>
-<span class="sourceLineNo">8138</span>    }<a name="line.8138"></a>
-<span class="sourceLineNo">8139</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8139"></a>
-<span class="sourceLineNo">8140</span>  }<a name="line.8140"></a>
-<span class="sourceLineNo">8141</span><a name="line.8141"></a>
-<span class="sourceLineNo">8142</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8142"></a>
-<span class="sourceLineNo">8143</span>                                  final byte[] columnFamily, final long now,<a name="line.8143"></a>
-<span class="sourceLineNo">8144</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8144"></a>
-<span class="sourceLineNo">8145</span>    // Forward any tags found on the delta.<a name="line.8145"></a>
-<span class="sourceLineNo">8146</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8146"></a>
-<span class="sourceLineNo">8147</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8147"></a>
-<span class="sourceLineNo">8148</span>    if (currentCell != null) {<a name="line.8148"></a>
-<span class="sourceLineNo">8149</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8149"></a>
-<span class="sourceLineNo">8150</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8150"></a>
-<span class="sourceLineNo">8151</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8151"></a>
-<span class="sourceLineNo">8152</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8152"></a>
-<span class="sourceLineNo">8153</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8153"></a>
-<span class="sourceLineNo">8154</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8154"></a>
-<span class="sourceLineNo">8155</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8155"></a>
-<span class="sourceLineNo">8156</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8156"></a>
-<span class="sourceLineNo">8157</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8157"></a>
-<span class="sourceLineNo">8158</span>              .setValue(newValue, 0, newValue.length)<a name="line.8158"></a>
-<span class="sourceLineNo">8159</span>              .setTags(TagUtil.fromList(tags))<a name="line.8159"></a>
-<span class="sourceLineNo">8160</span>              .build();<a name="line.8160"></a>
-<span class="sourceLineNo">8161</span>    } else {<a name="line.8161"></a>
-<span class="sourceLineNo">8162</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8162"></a>
-<span class="sourceLineNo">8163</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8163"></a>
-<span class="sourceLineNo">8164</span>    }<a name="line.8164"></a>
-<span class="sourceLineNo">8165</span>  }<a name="line.8165"></a>
-<span class="sourceLineNo">8166</span><a name="line.8166"></a>
-<span class="sourceLineNo">8167</span>  /**<a name="line.8167"></a>
-<span class="sourceLineNo">8168</span>   * @return Get the long out of the passed in Cell<a name="line.8168"></a>
-<span class="sourceLineNo">8169</span>   */<a name="line.8169"></a>
-<span class="sourceLineNo">8170</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8170"></a>
-<span class="sourceLineNo">8171</span>    int len = cell.getValueLength();<a name="line.8171"></a>
-<span class="sourceLineNo">8172</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8172"></a>
-<span class="sourceLineNo">8173</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8173"></a>
-<span class="sourceLineNo">8174</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8174"></a>
-<span class="sourceLineNo">8175</span>    }<a name="line.8175"></a>
-<span class="sourceLineNo">8176</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8176"></a>
-<span class="sourceLineNo">8177</span>  }<a name="line.8177"></a>
-<span class="sourceLineNo">8178</span><a name="line.8178"></a>
-<span class="sourceLineNo">8179</span>  /**<a name="line.8179"></a>
-<span class="sourceLineNo">8180</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8180"></a>
-<span class="sourceLineNo">8181</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8181"></a>
-<span class="sourceLineNo">8182</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8182"></a>
-<span class="sourceLineNo">8183</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8183"></a>
-<span class="sourceLineNo">8184</span>   * @return Return list of Cells found.<a name="line.8184"></a>
-<span class="sourceLineNo">8185</span>   */<a name="line.8185"></a>
-<span class="sourceLineNo">8186</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8186"></a>
-<span class="sourceLineNo">8187</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8187"></a>
-<span class="sourceLineNo">8188</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8188"></a>
-<span class="sourceLineNo">8189</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8189"></a>
-<span class="sourceLineNo">8190</span>    // client since cells are in an array list.<a name="line.8190"></a>
-<span class="sourceLineNo">8191</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8191"></a>
-<span class="sourceLineNo">8192</span>    sort(coordinates, store.getComparator());<a name="line.8192"></a>
-<span class="sourceLineNo">8193</span>    Get get = new Get(mutation.getRow());<a name="line.8193"></a>
-<span class="sourceLineNo">8194</span>    if (isolation != null) {<a name="line.8194"></a>
-<span class="sourceLineNo">8195</span>      get.setIsolationLevel(isolation);<a name="line.8195"></a>
-<span class="sourceLineNo">8196</span>    }<a name="line.8196"></a>
-<span class="sourceLineNo">8197</span>    for (Cell cell: coordinates) {<a name="line.8197"></a>
-<span class="sourceLineNo">8198</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8198"></a>
+<span class="sourceLineNo">8080</span>      case APPEND:<a name="line.8080"></a>
+<span class="sourceLineNo">8081</span>        tr = ((Append)mutation).getTimeRange();<a name="line.8081"></a>
+<span class="sourceLineNo">8082</span>        break;<a name="line.8082"></a>
+<span class="sourceLineNo">8083</span>      default:<a name="line.8083"></a>
+<span class="sourceLineNo">8084</span>        break;<a name="line.8084"></a>
+<span class="sourceLineNo">8085</span>    }<a name="line.8085"></a>
+<span class="sourceLineNo">8086</span>    List&lt;Cell&gt; currentValues = get(mutation, store, deltas,null, tr);<a name="line.8086"></a>
+<span class="sourceLineNo">8087</span>    // Iterate the input columns and update existing values if they were found, otherwise<a name="line.8087"></a>
+<span class="sourceLineNo">8088</span>    // add new column initialized to the delta amount<a name="line.8088"></a>
+<span class="sourceLineNo">8089</span>    int currentValuesIndex = 0;<a name="line.8089"></a>
+<span class="sourceLineNo">8090</span>    for (int i = 0; i &lt; deltas.size(); i++) {<a name="line.8090"></a>
+<span class="sourceLineNo">8091</span>      Cell delta = deltas.get(i);<a name="line.8091"></a>
+<span class="sourceLineNo">8092</span>      Cell currentValue = null;<a name="line.8092"></a>
+<span class="sourceLineNo">8093</span>      if (currentValuesIndex &lt; currentValues.size() &amp;&amp;<a name="line.8093"></a>
+<span class="sourceLineNo">8094</span>          CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)) {<a name="line.8094"></a>
+<span class="sourceLineNo">8095</span>        currentValue = currentValues.get(currentValuesIndex);<a name="line.8095"></a>
+<span class="sourceLineNo">8096</span>        if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {<a name="line.8096"></a>
+<span class="sourceLineNo">8097</span>          currentValuesIndex++;<a name="line.8097"></a>
+<span class="sourceLineNo">8098</span>        }<a name="line.8098"></a>
+<span class="sourceLineNo">8099</span>      }<a name="line.8099"></a>
+<span class="sourceLineNo">8100</span><a name="line.8100"></a>
+<span class="sourceLineNo">8101</span>      // Switch on whether this an increment or an append building the new Cell to apply.<a name="line.8101"></a>
+<span class="sourceLineNo">8102</span>      Cell newCell = null;<a name="line.8102"></a>
+<span class="sourceLineNo">8103</span>      switch (op) {<a name="line.8103"></a>
+<span class="sourceLineNo">8104</span>        case INCREMENT:<a name="line.8104"></a>
+<span class="sourceLineNo">8105</span>          long deltaAmount = getLongValue(delta);<a name="line.8105"></a>
+<span class="sourceLineNo">8106</span>          final long newValue = currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;<a name="line.8106"></a>
+<span class="sourceLineNo">8107</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt; Bytes.toBytes(newValue));<a name="line.8107"></a>
+<span class="sourceLineNo">8108</span>          break;<a name="line.8108"></a>
+<span class="sourceLineNo">8109</span>        case APPEND:<a name="line.8109"></a>
+<span class="sourceLineNo">8110</span>          newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation, (oldCell) -&gt;<a name="line.8110"></a>
+<span class="sourceLineNo">8111</span>            ByteBuffer.wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])<a name="line.8111"></a>
+<span class="sourceLineNo">8112</span>                    .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())<a name="line.8112"></a>
+<span class="sourceLineNo">8113</span>                    .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())<a name="line.8113"></a>
+<span class="sourceLineNo">8114</span>                    .array()<a name="line.8114"></a>
+<span class="sourceLineNo">8115</span>          );<a name="line.8115"></a>
+<span class="sourceLineNo">8116</span>          break;<a name="line.8116"></a>
+<span class="sourceLineNo">8117</span>        default: throw new UnsupportedOperationException(op.toString());<a name="line.8117"></a>
+<span class="sourceLineNo">8118</span>      }<a name="line.8118"></a>
+<span class="sourceLineNo">8119</span>      int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);<a name="line.8119"></a>
+<span class="sourceLineNo">8120</span>      if (newCellSize &gt; this.maxCellSize) {<a name="line.8120"></a>
+<span class="sourceLineNo">8121</span>        String msg = "Cell with size " + newCellSize + " exceeds limit of " +<a name="line.8121"></a>
+<span class="sourceLineNo">8122</span>            this.maxCellSize + " bytes";<a name="line.8122"></a>
+<span class="sourceLineNo">8123</span>        if (LOG.isDebugEnabled()) {<a name="line.8123"></a>
+<span class="sourceLineNo">8124</span>          LOG.debug(msg);<a name="line.8124"></a>
+<span class="sourceLineNo">8125</span>        }<a name="line.8125"></a>
+<span class="sourceLineNo">8126</span>        throw new DoNotRetryIOException(msg);<a name="line.8126"></a>
+<span class="sourceLineNo">8127</span>      }<a name="line.8127"></a>
+<span class="sourceLineNo">8128</span>      cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));<a name="line.8128"></a>
+<span class="sourceLineNo">8129</span>      // Add to results to get returned to the Client. If null, cilent does not want results.<a name="line.8129"></a>
+<span class="sourceLineNo">8130</span>      if (results != null) {<a name="line.8130"></a>
+<span class="sourceLineNo">8131</span>        results.add(newCell);<a name="line.8131"></a>
+<span class="sourceLineNo">8132</span>      }<a name="line.8132"></a>
+<span class="sourceLineNo">8133</span>    }<a name="line.8133"></a>
+<span class="sourceLineNo">8134</span><a name="line.8134"></a>
+<span class="sourceLineNo">8135</span>    // Give coprocessors a chance to update the new cells before apply to WAL or memstore<a name="line.8135"></a>
+<span class="sourceLineNo">8136</span>    if (coprocessorHost != null) {<a name="line.8136"></a>
+<span class="sourceLineNo">8137</span>      // Here the operation must be increment or append.<a name="line.8137"></a>
+<span class="sourceLineNo">8138</span>      cellPairs = op == Operation.INCREMENT ?<a name="line.8138"></a>
+<span class="sourceLineNo">8139</span>          coprocessorHost.postIncrementBeforeWAL(mutation, cellPairs) :<a name="line.8139"></a>
+<span class="sourceLineNo">8140</span>          coprocessorHost.postAppendBeforeWAL(mutation, cellPairs);<a name="line.8140"></a>
+<span class="sourceLineNo">8141</span>    }<a name="line.8141"></a>
+<span class="sourceLineNo">8142</span>    return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());<a name="line.8142"></a>
+<span class="sourceLineNo">8143</span>  }<a name="line.8143"></a>
+<span class="sourceLineNo">8144</span><a name="line.8144"></a>
+<span class="sourceLineNo">8145</span>  private static Cell reckonDelta(final Cell delta, final Cell currentCell,<a name="line.8145"></a>
+<span class="sourceLineNo">8146</span>                                  final byte[] columnFamily, final long now,<a name="line.8146"></a>
+<span class="sourceLineNo">8147</span>                                  Mutation mutation, Function&lt;Cell, byte[]&gt; supplier) throws IOException {<a name="line.8147"></a>
+<span class="sourceLineNo">8148</span>    // Forward any tags found on the delta.<a name="line.8148"></a>
+<span class="sourceLineNo">8149</span>    List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);<a name="line.8149"></a>
+<span class="sourceLineNo">8150</span>    tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());<a name="line.8150"></a>
+<span class="sourceLineNo">8151</span>    if (currentCell != null) {<a name="line.8151"></a>
+<span class="sourceLineNo">8152</span>      tags = TagUtil.carryForwardTags(tags, currentCell);<a name="line.8152"></a>
+<span class="sourceLineNo">8153</span>      byte[] newValue = supplier.apply(currentCell);<a name="line.8153"></a>
+<span class="sourceLineNo">8154</span>      return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)<a name="line.8154"></a>
+<span class="sourceLineNo">8155</span>              .setRow(mutation.getRow(), 0, mutation.getRow().length)<a name="line.8155"></a>
+<span class="sourceLineNo">8156</span>              .setFamily(columnFamily, 0, columnFamily.length)<a name="line.8156"></a>
+<span class="sourceLineNo">8157</span>              // copy the qualifier if the cell is located in shared memory.<a name="line.8157"></a>
+<span class="sourceLineNo">8158</span>              .setQualifier(CellUtil.cloneQualifier(delta))<a name="line.8158"></a>
+<span class="sourceLineNo">8159</span>              .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))<a name="line.8159"></a>
+<span class="sourceLineNo">8160</span>              .setType(KeyValue.Type.Put.getCode())<a name="line.8160"></a>
+<span class="sourceLineNo">8161</span>              .setValue(newValue, 0, newValue.length)<a name="line.8161"></a>
+<span class="sourceLineNo">8162</span>              .setTags(TagUtil.fromList(tags))<a name="line.8162"></a>
+<span class="sourceLineNo">8163</span>              .build();<a name="line.8163"></a>
+<span class="sourceLineNo">8164</span>    } else {<a name="line.8164"></a>
+<span class="sourceLineNo">8165</span>      PrivateCellUtil.updateLatestStamp(delta, now);<a name="line.8165"></a>
+<span class="sourceLineNo">8166</span>      return CollectionUtils.isEmpty(tags) ? delta : PrivateCellUtil.createCell(delta, tags);<a name="line.8166"></a>
+<span class="sourceLineNo">8167</span>    }<a name="line.8167"></a>
+<span class="sourceLineNo">8168</span>  }<a name="line.8168"></a>
+<span class="sourceLineNo">8169</span><a name="line.8169"></a>
+<span class="sourceLineNo">8170</span>  /**<a name="line.8170"></a>
+<span class="sourceLineNo">8171</span>   * @return Get the long out of the passed in Cell<a name="line.8171"></a>
+<span class="sourceLineNo">8172</span>   */<a name="line.8172"></a>
+<span class="sourceLineNo">8173</span>  private static long getLongValue(final Cell cell) throws DoNotRetryIOException {<a name="line.8173"></a>
+<span class="sourceLineNo">8174</span>    int len = cell.getValueLength();<a name="line.8174"></a>
+<span class="sourceLineNo">8175</span>    if (len != Bytes.SIZEOF_LONG) {<a name="line.8175"></a>
+<span class="sourceLineNo">8176</span>      // throw DoNotRetryIOException instead of IllegalArgumentException<a name="line.8176"></a>
+<span class="sourceLineNo">8177</span>      throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");<a name="line.8177"></a>
+<span class="sourceLineNo">8178</span>    }<a name="line.8178"></a>
+<span class="sourceLineNo">8179</span>    return PrivateCellUtil.getValueAsLong(cell);<a name="line.8179"></a>
+<span class="sourceLineNo">8180</span>  }<a name="line.8180"></a>
+<span class="sourceLineNo">8181</span><a name="line.8181"></a>
+<span class="sourceLineNo">8182</span>  /**<a name="line.8182"></a>
+<span class="sourceLineNo">8183</span>   * Do a specific Get on passed &lt;code&gt;columnFamily&lt;/code&gt; and column qualifiers.<a name="line.8183"></a>
+<span class="sourceLineNo">8184</span>   * @param mutation Mutation we are doing this Get for.<a name="line.8184"></a>
+<span class="sourceLineNo">8185</span>   * @param store Which column family on row (TODO: Go all Gets in one go)<a name="line.8185"></a>
+<span class="sourceLineNo">8186</span>   * @param coordinates Cells from &lt;code&gt;mutation&lt;/code&gt; used as coordinates applied to Get.<a name="line.8186"></a>
+<span class="sourceLineNo">8187</span>   * @return Return list of Cells found.<a name="line.8187"></a>
+<span class="sourceLineNo">8188</span>   */<a name="line.8188"></a>
+<span class="sourceLineNo">8189</span>  private List&lt;Cell&gt; get(Mutation mutation, HStore store, List&lt;Cell&gt; coordinates,<a name="line.8189"></a>
+<span class="sourceLineNo">8190</span>      IsolationLevel isolation, TimeRange tr) throws IOException {<a name="line.8190"></a>
+<span class="sourceLineNo">8191</span>    // Sort the cells so that they match the order that they appear in the Get results. Otherwise,<a name="line.8191"></a>
+<span class="sourceLineNo">8192</span>    // we won't be able to find the existing values if the cells are not specified in order by the<a name="line.8192"></a>
+<span class="sourceLineNo">8193</span>    // client since cells are in an array list.<a name="line.8193"></a>
+<span class="sourceLineNo">8194</span>    // TODO: I don't get why we are sorting. St.Ack 20150107<a name="line.8194"></a>
+<span class="sourceLineNo">8195</span>    sort(coordinates, store.getComparator());<a name="line.8195"></a>
+<span class="sourceLineNo">8196</span>    Get get = new Get(mutation.getRow());<a name="line.8196"></a>
+<span class="sourceLineNo">8197</span>    if (isolation != null) {<a name="line.8197"></a>
+<span class="sourceLineNo">8198</span>      get.setIsolationLevel(isolation);<a name="line.8198"></a>
 <span class="sourceLineNo">8199</span>    }<a name="line.8199"></a>
-<span class="sourceLineNo">8200</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8200"></a>
-<span class="sourceLineNo">8201</span>    if (tr != null) {<a name="line.8201"></a>
-<span class="sourceLineNo">8202</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8202"></a>
-<span class="sourceLineNo">8203</span>    }<a name="line.8203"></a>
-<span class="sourceLineNo">8204</span>    return get(get, false);<a name="line.8204"></a>
-<span class="sourceLineNo">8205</span>  }<a name="line.8205"></a>
-<span class="sourceLineNo">8206</span><a name="line.8206"></a>
-<span class="sourceLineNo">8207</span>  /**<a name="line.8207"></a>
-<span class="sourceLineNo">8208</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8208"></a>
-<span class="sourceLineNo">8209</span>   */<a name="line.8209"></a>
-<span class="sourceLineNo">8210</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8210"></a>
-<span class="sourceLineNo">8211</span>    cells.sort(comparator);<a name="line.8211"></a>
-<span class="sourceLineNo">8212</span>    return cells;<a name="line.8212"></a>
-<span class="sourceLineNo">8213</span>  }<a name="line.8213"></a>
-<span class="sourceLineNo">8214</span><a name="line.8214"></a>
-<span class="sourceLineNo">8215</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8215"></a>
-<span class="sourceLineNo">8216</span>      ClassSize.OBJECT +<a name="line.8216"></a>
-<span class="sourceLineNo">8217</span>      ClassSize.ARRAY +<a name="line.8217"></a>
-<span class="sourceLineNo">8218</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8218"></a>
-<span class="sourceLineNo">8219</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8219"></a>
-<span class="sourceLineNo">8220</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8220"></a>
-<span class="sourceLineNo">8221</span><a name="line.8221"></a>
-<span class="sourceLineNo">8222</span>  // woefully out of date - currently missing:<a name="line.8222"></a>
-<span class="sourceLineNo">8223</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8223"></a>
-<span class="sourceLineNo">8224</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8224"></a>
-<span class="sourceLineNo">8225</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8225"></a>
-<span class="sourceLineNo">8226</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8226"></a>
-<span class="sourceLineNo">8227</span>  // 1 x HRegion$WriteState - writestate<a name="line.8227"></a>
-<span class="sourceLineNo">8228</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8228"></a>
-<span class="sourceLineNo">8229</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8229"></a>
-<span class="sourceLineNo">8230</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8230"></a>
-<span class="sourceLineNo">8231</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8231"></a>
-<span class="sourceLineNo">8232</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8232"></a>
-<span class="sourceLineNo">8233</span>      ClassSize.OBJECT + // closeLock<a name="line.8233"></a>
-<span class="sourceLineNo">8234</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8234"></a>
-<span class="sourceLineNo">8235</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8235"></a>
-<span class="sourceLineNo">8236</span>                                    // compactionsFailed<a name="line.8236"></a>
-<span class="sourceLineNo">8237</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8237"></a>
-<span class="sourceLineNo">8238</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8238"></a>
-<span class="sourceLineNo">8239</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8239"></a>
-<span class="sourceLineNo">8240</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8240"></a>
-<span class="sourceLineNo">8241</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8241"></a>
-<span class="sourceLineNo">8242</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8242"></a>
-<span class="sourceLineNo">8243</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8243"></a>
-<span class="sourceLineNo">8244</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8244"></a>
-<span class="sourceLineNo">8245</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8245"></a>
-<span class="sourceLineNo">8246</span>      ;<a name="line.8246"></a>
-<span class="sourceLineNo">8247</span><a name="line.8247"></a>
-<span class="sourceLineNo">8248</span>  @Override<a name="line.8248"></a>
-<span class="sourceLineNo">8249</span>  public long heapSize() {<a name="line.8249"></a>
-<span class="sourceLineNo">8250</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8250"></a>
-<span class="sourceLineNo">8251</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8251"></a>
-<span class="sourceLineNo">8252</span>  }<a name="line.8252"></a>
-<span class="sourceLineNo">8253</span><a name="line.8253"></a>
-<span class="sourceLineNo">8254</span>  /**<a name="line.8254"></a>
-<span class="sourceLineNo">8255</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8255"></a>
-<span class="sourceLineNo">8256</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8256"></a>
-<span class="sourceLineNo">8257</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8257"></a>
-<span class="sourceLineNo">8258</span>   *<a name="line.8258"></a>
-<span class="sourceLineNo">8259</span>   * &lt;p&gt;<a name="line.8259"></a>
-<span class="sourceLineNo">8260</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8260"></a>
-<span class="sourceLineNo">8261</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8261"></a>
-<span class="sourceLineNo">8262</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8262"></a>
-<span class="sourceLineNo">8263</span>   * a return value of {@code false}.<a name="line.8263"></a>
-<span class="sourceLineNo">8264</span>   * &lt;/p&gt;<a name="line.8264"></a>
-<span class="sourceLineNo">8265</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8265"></a>
-<span class="sourceLineNo">8266</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8266"></a>
-<span class="sourceLineNo">8267</span>   * otherwise<a name="line.8267"></a>
-<span class="sourceLineNo">8268</span>   */<a name="line.8268"></a>
-<span class="sourceLineNo">8269</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8269"></a>
-<span class="sourceLineNo">8270</span>    /*<a name="line.8270"></a>
-<span class="sourceLineNo">8271</span>     * No stacking of instances is allowed for a single service name<a name="line.8271"></a>
-<span class="sourceLineNo">8272</span>     */<a name="line.8272"></a>
-<span class="sourceLineNo">8273</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8273"></a>
-<span class="sourceLineNo">8274</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8274"></a>
-<span class="sourceLineNo">8275</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8275"></a>
-<span class="sourceLineNo">8276</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8276"></a>
-<span class="sourceLineNo">8277</span>          " already registered, rejecting request from " + instance);<a name="line.8277"></a>
-<span class="sourceLineNo">8278</span>      return false;<a name="line.8278"></a>
-<span class="sourceLineNo">8279</span>    }<a name="line.8279"></a>
-<span class="sourceLineNo">8280</span><a name="line.8280"></a>
-<span class="sourceLineNo">8281</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8281"></a>
-<span class="sourceLineNo">8282</span>    if (LOG.isDebugEnabled()) {<a name="line.8282"></a>
-<span class="sourceLineNo">8283</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8283"></a>
-<span class="sourceLineNo">8284</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8284"></a>
-<span class="sourceLineNo">8285</span>          " service=" + serviceName);<a name="line.8285"></a>
-<span class="sourceLineNo">8286</span>    }<a name="line.8286"></a>
-<span class="sourceLineNo">8287</span>    return true;<a name="line.8287"></a>
-<span class="sourceLineNo">8288</span>  }<a name="line.8288"></a>
-<span class="sourceLineNo">8289</span><a name="line.8289"></a>
-<span class="sourceLineNo">8290</span>  /**<a name="line.8290"></a>
-<span class="sourceLineNo">8291</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8291"></a>
-<span class="sourceLineNo">8292</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8292"></a>
-<span class="sourceLineNo">8293</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8293"></a>
-<span class="sourceLineNo">8294</span>   * method before they are available.<a name="line.8294"></a>
-<span class="sourceLineNo">8295</span>   *<a name="line.8295"></a>
-<span class="sourceLineNo">8296</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8296"></a>
-<span class="sourceLineNo">8297</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8297"></a>
-<span class="sourceLineNo">8298</span>   *     and parameters for the method invocation<a name="line.8298"></a>
-<span class="sourceLineNo">8299</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8299"></a>
-<span class="sourceLineNo">8300</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8300"></a>
-<span class="sourceLineNo">8301</span>   *     occurs during the invocation<a name="line.8301"></a>
-<span class="sourceLineNo">8302</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8302"></a>
-<span class="sourceLineNo">8303</span>   */<a name="line.8303"></a>
-<span class="sourceLineNo">8304</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8304"></a>
-<span class="sourceLineNo">8305</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8305"></a>
-<span class="sourceLineNo">8306</span>    String serviceName = call.getServiceName();<a name="line.8306"></a>
-<span class="sourceLineNo">8307</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8307"></a>
-<span class="sourceLineNo">8308</span>    if (service == null) {<a name="line.8308"></a>
-<span class="sourceLineNo">8309</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8309"></a>
-<span class="sourceLineNo">8310</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8310"></a>
-<span class="sourceLineNo">8311</span>    }<a name="line.8311"></a>
-<span class="sourceLineNo">8312</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8312"></a>
-<span class="sourceLineNo">8313</span><a name="line.8313"></a>
-<span class="sourceLineNo">8314</span>    cpRequestsCount.increment();<a name="line.8314"></a>
-<span class="sourceLineNo">8315</span>    String methodName = call.getMethodName();<a name="line.8315"></a>
-<span class="sourceLineNo">8316</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8316"></a>
-<span class="sourceLineNo">8317</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8317"></a>
-<span class="sourceLineNo">8318</span><a name="line.8318"></a>
-<span class="sourceLineNo">8319</span>    com.google.protobuf.Message.Builder builder =<a name="line.8319"></a>
-<span class="sourceLineNo">8320</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8320"></a>
+<span class="sourceLineNo">8200</span>    for (Cell cell: coordinates) {<a name="line.8200"></a>
+<span class="sourceLineNo">8201</span>      get.addColumn(store.getColumnFamilyDescriptor().getName(), CellUtil.cloneQualifier(cell));<a name="line.8201"></a>
+<span class="sourceLineNo">8202</span>    }<a name="line.8202"></a>
+<span class="sourceLineNo">8203</span>    // Increments carry time range. If an Increment instance, put it on the Get.<a name="line.8203"></a>
+<span class="sourceLineNo">8204</span>    if (tr != null) {<a name="line.8204"></a>
+<span class="sourceLineNo">8205</span>      get.setTimeRange(tr.getMin(), tr.getMax());<a name="line.8205"></a>
+<span class="sourceLineNo">8206</span>    }<a name="line.8206"></a>
+<span class="sourceLineNo">8207</span>    return get(get, false);<a name="line.8207"></a>
+<span class="sourceLineNo">8208</span>  }<a name="line.8208"></a>
+<span class="sourceLineNo">8209</span><a name="line.8209"></a>
+<span class="sourceLineNo">8210</span>  /**<a name="line.8210"></a>
+<span class="sourceLineNo">8211</span>   * @return Sorted list of &lt;code&gt;cells&lt;/code&gt; using &lt;code&gt;comparator&lt;/code&gt;<a name="line.8211"></a>
+<span class="sourceLineNo">8212</span>   */<a name="line.8212"></a>
+<span class="sourceLineNo">8213</span>  private static List&lt;Cell&gt; sort(List&lt;Cell&gt; cells, final CellComparator comparator) {<a name="line.8213"></a>
+<span class="sourceLineNo">8214</span>    cells.sort(comparator);<a name="line.8214"></a>
+<span class="sourceLineNo">8215</span>    return cells;<a name="line.8215"></a>
+<span class="sourceLineNo">8216</span>  }<a name="line.8216"></a>
+<span class="sourceLineNo">8217</span><a name="line.8217"></a>
+<span class="sourceLineNo">8218</span>  public static final long FIXED_OVERHEAD = ClassSize.align(<a name="line.8218"></a>
+<span class="sourceLineNo">8219</span>      ClassSize.OBJECT +<a name="line.8219"></a>
+<span class="sourceLineNo">8220</span>      ClassSize.ARRAY +<a name="line.8220"></a>
+<span class="sourceLineNo">8221</span>      55 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +<a name="line.8221"></a>
+<span class="sourceLineNo">8222</span>      (15 * Bytes.SIZEOF_LONG) +<a name="line.8222"></a>
+<span class="sourceLineNo">8223</span>      3 * Bytes.SIZEOF_BOOLEAN);<a name="line.8223"></a>
+<span class="sourceLineNo">8224</span><a name="line.8224"></a>
+<span class="sourceLineNo">8225</span>  // woefully out of date - currently missing:<a name="line.8225"></a>
+<span class="sourceLineNo">8226</span>  // 1 x HashMap - coprocessorServiceHandlers<a name="line.8226"></a>
+<span class="sourceLineNo">8227</span>  // 6 x LongAdder - numMutationsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8227"></a>
+<span class="sourceLineNo">8228</span>  //   checkAndMutateChecksPassed, checkAndMutateChecksFailed, readRequestsCount,<a name="line.8228"></a>
+<span class="sourceLineNo">8229</span>  //   writeRequestsCount, cpRequestsCount<a name="line.8229"></a>
+<span class="sourceLineNo">8230</span>  // 1 x HRegion$WriteState - writestate<a name="line.8230"></a>
+<span class="sourceLineNo">8231</span>  // 1 x RegionCoprocessorHost - coprocessorHost<a name="line.8231"></a>
+<span class="sourceLineNo">8232</span>  // 1 x RegionSplitPolicy - splitPolicy<a name="line.8232"></a>
+<span class="sourceLineNo">8233</span>  // 1 x MetricsRegion - metricsRegion<a name="line.8233"></a>
+<span class="sourceLineNo">8234</span>  // 1 x MetricsRegionWrapperImpl - metricsRegionWrapper<a name="line.8234"></a>
+<span class="sourceLineNo">8235</span>  public static final long DEEP_OVERHEAD = FIXED_OVERHEAD +<a name="line.8235"></a>
+<span class="sourceLineNo">8236</span>      ClassSize.OBJECT + // closeLock<a name="line.8236"></a>
+<span class="sourceLineNo">8237</span>      (2 * ClassSize.ATOMIC_BOOLEAN) + // closed, closing<a name="line.8237"></a>
+<span class="sourceLineNo">8238</span>      (3 * ClassSize.ATOMIC_LONG) + // numPutsWithoutWAL, dataInMemoryWithoutWAL,<a name="line.8238"></a>
+<span class="sourceLineNo">8239</span>                                    // compactionsFailed<a name="line.8239"></a>
+<span class="sourceLineNo">8240</span>      (2 * ClassSize.CONCURRENT_HASHMAP) +  // lockedRows, scannerReadPoints<a name="line.8240"></a>
+<span class="sourceLineNo">8241</span>      WriteState.HEAP_SIZE + // writestate<a name="line.8241"></a>
+<span class="sourceLineNo">8242</span>      ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY + // stores<a name="line.8242"></a>
+<span class="sourceLineNo">8243</span>      (2 * ClassSize.REENTRANT_LOCK) + // lock, updatesLock<a name="line.8243"></a>
+<span class="sourceLineNo">8244</span>      MultiVersionConcurrencyControl.FIXED_SIZE // mvcc<a name="line.8244"></a>
+<span class="sourceLineNo">8245</span>      + 2 * ClassSize.TREEMAP // maxSeqIdInStores, replicationScopes<a name="line.8245"></a>
+<span class="sourceLineNo">8246</span>      + 2 * ClassSize.ATOMIC_INTEGER // majorInProgress, minorInProgress<a name="line.8246"></a>
+<span class="sourceLineNo">8247</span>      + ClassSize.STORE_SERVICES // store services<a name="line.8247"></a>
+<span class="sourceLineNo">8248</span>      + StoreHotnessProtector.FIXED_SIZE<a name="line.8248"></a>
+<span class="sourceLineNo">8249</span>      ;<a name="line.8249"></a>
+<span class="sourceLineNo">8250</span><a name="line.8250"></a>
+<span class="sourceLineNo">8251</span>  @Override<a name="line.8251"></a>
+<span class="sourceLineNo">8252</span>  public long heapSize() {<a name="line.8252"></a>
+<span class="sourceLineNo">8253</span>    // this does not take into account row locks, recent flushes, mvcc entries, and more<a name="line.8253"></a>
+<span class="sourceLineNo">8254</span>    return DEEP_OVERHEAD + stores.values().stream().mapToLong(HStore::heapSize).sum();<a name="line.8254"></a>
+<span class="sourceLineNo">8255</span>  }<a name="line.8255"></a>
+<span class="sourceLineNo">8256</span><a name="line.8256"></a>
+<span class="sourceLineNo">8257</span>  /**<a name="line.8257"></a>
+<span class="sourceLineNo">8258</span>   * Registers a new protocol buffer {@link Service} subclass as a coprocessor endpoint to<a name="line.8258"></a>
+<span class="sourceLineNo">8259</span>   * be available for handling Region#execService(com.google.protobuf.RpcController,<a name="line.8259"></a>
+<span class="sourceLineNo">8260</span>   *    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall) calls.<a name="line.8260"></a>
+<span class="sourceLineNo">8261</span>   *<a name="line.8261"></a>
+<span class="sourceLineNo">8262</span>   * &lt;p&gt;<a name="line.8262"></a>
+<span class="sourceLineNo">8263</span>   * Only a single instance may be registered per region for a given {@link Service} subclass (the<a name="line.8263"></a>
+<span class="sourceLineNo">8264</span>   * instances are keyed on {@link com.google.protobuf.Descriptors.ServiceDescriptor#getFullName()}.<a name="line.8264"></a>
+<span class="sourceLineNo">8265</span>   * After the first registration, subsequent calls with the same service name will fail with<a name="line.8265"></a>
+<span class="sourceLineNo">8266</span>   * a return value of {@code false}.<a name="line.8266"></a>
+<span class="sourceLineNo">8267</span>   * &lt;/p&gt;<a name="line.8267"></a>
+<span class="sourceLineNo">8268</span>   * @param instance the {@code Service} subclass instance to expose as a coprocessor endpoint<a name="line.8268"></a>
+<span class="sourceLineNo">8269</span>   * @return {@code true} if the registration was successful, {@code false}<a name="line.8269"></a>
+<span class="sourceLineNo">8270</span>   * otherwise<a name="line.8270"></a>
+<span class="sourceLineNo">8271</span>   */<a name="line.8271"></a>
+<span class="sourceLineNo">8272</span>  public boolean registerService(com.google.protobuf.Service instance) {<a name="line.8272"></a>
+<span class="sourceLineNo">8273</span>    /*<a name="line.8273"></a>
+<span class="sourceLineNo">8274</span>     * No stacking of instances is allowed for a single service name<a name="line.8274"></a>
+<span class="sourceLineNo">8275</span>     */<a name="line.8275"></a>
+<span class="sourceLineNo">8276</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = instance.getDescriptorForType();<a name="line.8276"></a>
+<span class="sourceLineNo">8277</span>    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);<a name="line.8277"></a>
+<span class="sourceLineNo">8278</span>    if (coprocessorServiceHandlers.containsKey(serviceName)) {<a name="line.8278"></a>
+<span class="sourceLineNo">8279</span>      LOG.error("Coprocessor service " + serviceName +<a name="line.8279"></a>
+<span class="sourceLineNo">8280</span>          " already registered, rejecting request from " + instance);<a name="line.8280"></a>
+<span class="sourceLineNo">8281</span>      return false;<a name="line.8281"></a>
+<span class="sourceLineNo">8282</span>    }<a name="line.8282"></a>
+<span class="sourceLineNo">8283</span><a name="line.8283"></a>
+<span class="sourceLineNo">8284</span>    coprocessorServiceHandlers.put(serviceName, instance);<a name="line.8284"></a>
+<span class="sourceLineNo">8285</span>    if (LOG.isDebugEnabled()) {<a name="line.8285"></a>
+<span class="sourceLineNo">8286</span>      LOG.debug("Registered coprocessor service: region=" +<a name="line.8286"></a>
+<span class="sourceLineNo">8287</span>          Bytes.toStringBinary(getRegionInfo().getRegionName()) +<a name="line.8287"></a>
+<span class="sourceLineNo">8288</span>          " service=" + serviceName);<a name="line.8288"></a>
+<span class="sourceLineNo">8289</span>    }<a name="line.8289"></a>
+<span class="sourceLineNo">8290</span>    return true;<a name="line.8290"></a>
+<span class="sourceLineNo">8291</span>  }<a name="line.8291"></a>
+<span class="sourceLineNo">8292</span><a name="line.8292"></a>
+<span class="sourceLineNo">8293</span>  /**<a name="line.8293"></a>
+<span class="sourceLineNo">8294</span>   * Executes a single protocol buffer coprocessor endpoint {@link Service} method using<a name="line.8294"></a>
+<span class="sourceLineNo">8295</span>   * the registered protocol handlers.  {@link Service} implementations must be registered via the<a name="line.8295"></a>
+<span class="sourceLineNo">8296</span>   * {@link #registerService(com.google.protobuf.Service)}<a name="line.8296"></a>
+<span class="sourceLineNo">8297</span>   * method before they are available.<a name="line.8297"></a>
+<span class="sourceLineNo">8298</span>   *<a name="line.8298"></a>
+<span class="sourceLineNo">8299</span>   * @param controller an {@code RpcContoller} implementation to pass to the invoked service<a name="line.8299"></a>
+<span class="sourceLineNo">8300</span>   * @param call a {@code CoprocessorServiceCall} instance identifying the service, method,<a name="line.8300"></a>
+<span class="sourceLineNo">8301</span>   *     and parameters for the method invocation<a name="line.8301"></a>
+<span class="sourceLineNo">8302</span>   * @return a protocol buffer {@code Message} instance containing the method's result<a name="line.8302"></a>
+<span class="sourceLineNo">8303</span>   * @throws IOException if no registered service handler is found or an error<a name="line.8303"></a>
+<span class="sourceLineNo">8304</span>   *     occurs during the invocation<a name="line.8304"></a>
+<span class="sourceLineNo">8305</span>   * @see #registerService(com.google.protobuf.Service)<a name="line.8305"></a>
+<span class="sourceLineNo">8306</span>   */<a name="line.8306"></a>
+<span class="sourceLineNo">8307</span>  public com.google.protobuf.Message execService(com.google.protobuf.RpcController controller,<a name="line.8307"></a>
+<span class="sourceLineNo">8308</span>      CoprocessorServiceCall call) throws IOException {<a name="line.8308"></a>
+<span class="sourceLineNo">8309</span>    String serviceName = call.getServiceName();<a name="line.8309"></a>
+<span class="sourceLineNo">8310</span>    com.google.protobuf.Service service = coprocessorServiceHandlers.get(serviceName);<a name="line.8310"></a>
+<span class="sourceLineNo">8311</span>    if (service == null) {<a name="line.8311"></a>
+<span class="sourceLineNo">8312</span>      throw new UnknownProtocolException(null, "No registered coprocessor service found for " +<a name="line.8312"></a>
+<span class="sourceLineNo">8313</span>          serviceName + " in region " + Bytes.toStringBinary(getRegionInfo().getRegionName()));<a name="line.8313"></a>
+<span class="sourceLineNo">8314</span>    }<a name="line.8314"></a>
+<span class="sourceLineNo">8315</span>    com.google.protobuf.Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();<a name="line.8315"></a>
+<span class="sourceLineNo">8316</span><a name="line.8316"></a>
+<span class="sourceLineNo">8317</span>    cpRequestsCount.increment();<a name="line.8317"></a>
+<span class="sourceLineNo">8318</span>    String methodName = call.getMethodName();<a name="line.8318"></a>
+<span class="sourceLineNo">8319</span>    com.google.protobuf.Descriptors.MethodDescriptor methodDesc =<a name="line.8319"></a>
+<span class="sourceLineNo">8320</span>        CoprocessorRpcUtils.getMethodDescriptor(methodName, serviceDesc);<a name="line.8320"></a>
 <span class="sourceLineNo">8321</span><a name="line.8321"></a>
-<span class="sourceLineNo">8322</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8322"></a>
-<span class="sourceLineNo">8323</span>        call.getRequest().toByteArray());<a name="line.8323"></a>
-<span class="sourceLineNo">8324</span>    com.google.protobuf.Message request =<a name="line.8324"></a>
-<span class="sourceLineNo">8325</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8325"></a>
-<span class="sourceLineNo">8326</span><a name="line.8326"></a>
-<span class="sourceLineNo">8327</span>    if (coprocessorHost != null) {<a name="line.8327"></a>
-<span class="sourceLineNo">8328</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8328"></a>
-<span class="sourceLineNo">8329</span>    }<a name="line.8329"></a>
-<span class="sourceLineNo">8330</span><a name="line.8330"></a>
-<span class="sourceLineNo">8331</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8331"></a>
-<span class="sourceLineNo">8332</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8332"></a>
-<span class="sourceLineNo">8333</span>    service.callMethod(methodDesc, controller, request,<a name="line.8333"></a>
-<span class="sourceLineNo">8334</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8334"></a>
-<span class="sourceLineNo">8335</span>      @Override<a name="line.8335"></a>
-<span class="sourceLineNo">8336</span>      public void run(com.google.protobuf.Message message) {<a name="line.8336"></a>
-<span class="sourceLineNo">8337</span>        if (message != null) {<a name="line.8337"></a>
-<span class="sourceLineNo">8338</span>          responseBuilder.mergeFrom(message);<a name="line.8338"></a>
-<span class="sourceLineNo">8339</span>        }<a name="line.8339"></a>
-<span class="sourceLineNo">8340</span>      }<a name="line.8340"></a>
-<span class="sourceLineNo">8341</span>    });<a name="line.8341"></a>
-<span class="sourceLineNo">8342</span><a name="line.8342"></a>
-<span class="sourceLineNo">8343</span>    if (coprocessorHost != null) {<a name="line.8343"></a>
-<span class="sourceLineNo">8344</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8344"></a>
-<span class="sourceLineNo">8345</span>    }<a name="line.8345"></a>
-<span class="sourceLineNo">8346</span>    IOException exception =<a name="line.8346"></a>
-<span class="sourceLineNo">8347</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8347"></a>
-<span class="sourceLineNo">8348</span>    if (exception != null) {<a name="line.8348"></a>
-<span class="sourceLineNo">8349</span>      throw exception;<a name="line.8349"></a>
-<span class="sourceLineNo">8350</span>    }<a name="line.8350"></a>
-<span class="sourceLineNo">8351</span><a name="line.8351"></a>
-<span class="sourceLineNo">8352</span>    return responseBuilder.build();<a name="line.8352"></a>
-<span class="sourceLineNo">8353</span>  }<a name="line.8353"></a>
+<span class="sourceLineNo">8322</span>    com.google.protobuf.Message.Builder builder =<a name="line.8322"></a>
+<span class="sourceLineNo">8323</span>        service.getRequestPrototype(methodDesc).newBuilderForType();<a name="line.8323"></a>
+<span class="sourceLineNo">8324</span><a name="line.8324"></a>
+<span class="sourceLineNo">8325</span>    org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builder,<a name="line.8325"></a>
+<span class="sourceLineNo">8326</span>        call.getRequest().toByteArray());<a name="line.8326"></a>
+<span class="sourceLineNo">8327</span>    com.google.protobuf.Message request =<a name="line.8327"></a>
+<span class="sourceLineNo">8328</span>        CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());<a name="line.8328"></a>
+<span class="sourceLineNo">8329</span><a name="line.8329"></a>
+<span class="sourceLineNo">8330</span>    if (coprocessorHost != null) {<a name="line.8330"></a>
+<span class="sourceLineNo">8331</span>      request = coprocessorHost.preEndpointInvocation(service, methodName, request);<a name="line.8331"></a>
+<span class="sourceLineNo">8332</span>    }<a name="line.8332"></a>
+<span class="sourceLineNo">8333</span><a name="line.8333"></a>
+<span class="sourceLineNo">8334</span>    final com.google.protobuf.Message.Builder responseBuilder =<a name="line.8334"></a>
+<span class="sourceLineNo">8335</span>        service.getResponsePrototype(methodDesc).newBuilderForType();<a name="line.8335"></a>
+<span class="sourceLineNo">8336</span>    service.callMethod(methodDesc, controller, request,<a name="line.8336"></a>
+<span class="sourceLineNo">8337</span>        new com.google.protobuf.RpcCallback&lt;com.google.protobuf.Message&gt;() {<a name="line.8337"></a>
+<span class="sourceLineNo">8338</span>      @Override<a name="line.8338"></a>
+<span class="sourceLineNo">8339</span>      public void run(com.google.protobuf.Message message) {<a name="line.8339"></a>
+<span class="sourceLineNo">8340</span>        if (message != null) {<a name="line.8340"></a>
+<span class="sourceLineNo">8341</span>          responseBuilder.mergeFrom(message);<a name="line.8341"></a>
+<span class="sourceLineNo">8342</span>        }<a name="line.8342"></a>
+<span class="sourceLineNo">8343</span>      }<a name="line.8343"></a>
+<span class="sourceLineNo">8344</span>    });<a name="line.8344"></a>
+<span class="sourceLineNo">8345</span><a name="line.8345"></a>
+<span class="sourceLineNo">8346</span>    if (coprocessorHost != null) {<a name="line.8346"></a>
+<span class="sourceLineNo">8347</span>      coprocessorHost.postEndpointInvocation(service, methodName, request, responseBuilder);<a name="line.8347"></a>
+<span class="sourceLineNo">8348</span>    }<a name="line.8348"></a>
+<span class="sourceLineNo">8349</span>    IOException exception =<a name="line.8349"></a>
+<span class="sourceLineNo">8350</span>        org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils.getControllerException(controller);<a name="line.8350"></a>
+<span class="sourceLineNo">8351</span>    if (exception != null) {<a name="line.8351"></a>
+<span class="sourceLineNo">8352</span>      throw exception;<a name="line.8352"></a>
+<span class="sourceLineNo">8353</span>    }<a name="line.8353"></a>
 <span class="sourceLineNo">8354</span><a name="line.8354"></a>
-<span class="sourceLineNo">8355</span>  boolean shouldForceSplit() {<a name="line.8355"></a>
-<span class="sourceLineNo">8356</span>    return this.splitRequest;<a name="line.8356"></a>
-<span class="sourceLineNo">8357</span>  }<a name="line.8357"></a>
-<span class="sourceLineNo">8358</span><a name="line.8358"></a>
-<span class="sourceLineNo">8359</span>  byte[] getExplicitSplitPoint() {<a name="line.8359"></a>
-<span class="sourceLineNo">8360</span>    return this.explicitSplitPoint;<a name="line.8360"></a>
-<span class="sourceLineNo">8361</span>  }<a name="line.8361"></a>
-<span class="sourceLineNo">8362</span><a name="line.8362"></a>
-<span class="sourceLineNo">8363</span>  void forceSplit(byte[] sp) {<a name="line.8363"></a>
-<span class="sourceLineNo">8364</span>    // This HRegion will go away after the forced split is successful<a name="line.8364"></a>
-<span class="sourceLineNo">8365</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8365"></a>
-<span class="sourceLineNo">8366</span>    this.splitRequest = true;<a name="line.8366"></a>
-<span class="sourceLineNo">8367</span>    if (sp != null) {<a name="line.8367"></a>
-<span class="sourceLineNo">8368</span>      this.explicitSplitPoint = sp;<a name="line.8368"></a>
-<span class="sourceLineNo">8369</span>    }<a name="line.8369"></a>
-<span class="sourceLineNo">8370</span>  }<a name="line.8370"></a>
-<span class="sourceLineNo">8371</span><a name="line.8371"></a>
-<span class="sourceLineNo">8372</span>  void clearSplit() {<a name="line.8372"></a>
-<span class="sourceLineNo">8373</span>    this.splitRequest = false;<a name="line.8373"></a>
-<span class="sourceLineNo">8374</span>    this.explicitSplitPoint = null;<a name="line.8374"></a>
-<span class="sourceLineNo">8375</span>  }<a name="line.8375"></a>
-<span class="sourceLineNo">8376</span><a name="line.8376"></a>
-<span class="sourceLineNo">8377</span>  /**<a name="line.8377"></a>
-<span class="sourceLineNo">8378</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8378"></a>
-<span class="sourceLineNo">8379</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8379"></a>
-<span class="sourceLineNo">8380</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8380"></a>
-<span class="sourceLineNo">8381</span>   * is based on the size of the store.<a name="line.8381"></a>
-<span class="sourceLineNo">8382</span>   */<a name="line.8382"></a>
-<span class="sourceLineNo">8383</span>  public byte[] checkSplit() {<a name="line.8383"></a>
-<span class="sourceLineNo">8384</span>    // Can't split META<a name="line.8384"></a>
-<span class="sourceLineNo">8385</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8385"></a>
-<span class="sourceLineNo">8386</span>      if (shouldForceSplit()) {<a name="line.8386"></a>
-<span class="sourceLineNo">8387</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8387"></a>
-<span class="sourceLineNo">8388</span>      }<a name="line.8388"></a>
-<span class="sourceLineNo">8389</span>      return null;<a name="line.8389"></a>
-<span class="sourceLineNo">8390</span>    }<a name="line.8390"></a>
-<span class="sourceLineNo">8391</span><a name="line.8391"></a>
-<span class="sourceLineNo">8392</span>    // Can't split a region that is closing.<a name="line.8392"></a>
-<span class="sourceLineNo">8393</span>    if (this.isClosing()) {<a name="line.8393"></a>
-<span class="sourceLineNo">8394</span>      return null;<a name="line.8394"></a>
-<span class="sourceLineNo">8395</span>    }<a name="line.8395"></a>
-<span class="sourceLineNo">8396</span><a name="line.8396"></a>
-<span class="sourceLineNo">8397</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8397"></a>
-<span class="sourceLineNo">8398</span>      return null;<a name="line.8398"></a>
-<span class="sourceLineNo">8399</span>    }<a name="line.8399"></a>
-<span class="sourceLineNo">8400</span><a name="line.8400"></a>
-<span class="sourceLineNo">8401</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8401"></a>
-<span class="sourceLineNo">8402</span><a name="line.8402"></a>
-<span class="sourceLineNo">8403</span>    if (ret != null) {<a name="line.8403"></a>
-<span class="sourceLineNo">8404</span>      try {<a name="line.8404"></a>
-<span class="sourceLineNo">8405</span>        checkRow(ret, "calculated split");<a name="line.8405"></a>
-<span class="sourceLineNo">8406</span>      } catch (IOException e) {<a name="line.8406"></a>
-<span class="sourceLineNo">8407</span>        LOG.error("Ignoring invalid split", e);<a name="line.8407"></a>
-<span class="sourceLineNo">8408</span>        return null;<a name="line.8408"></a>
-<span class="sourceLineNo">8409</span>      }<a name="line.8409"></a>
-<span class="sourceLineNo">8410</span>    }<a name="line.8410"></a>
-<span class="sourceLineNo">8411</span>    return ret;<a name="line.8411"></a>
-<span class="sourceLineNo">8412</span>  }<a name="line.8412"></a>
-<span class="sourceLineNo">8413</span><a name="line.8413"></a>
-<span class="sourceLineNo">8414</span>  /**<a name="line.8414"></a>
-<span class="sourceLineNo">8415</span>   * @return The priority that this region should have in the compaction queue<a name="line.8415"></a>
-<span class="sourceLineNo">8416</span>   */<a name="line.8416"></a>
-<span class="sourceLineNo">8417</span>  public int getCompactPriority() {<a name="line.8417"></a>
-<span class="sourceLineNo">8418</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8418"></a>
-<span class="sourceLineNo">8419</span>        .orElse(Store.NO_PRIORITY);<a name="line.8419"></a>
-<span class="sourceLineNo">8420</span>  }<a name="line.8420"></a>
-<span class="sourceLineNo">8421</span><a name="line.8421"></a>
-<span class="sourceLineNo">8422</span>  /** @return the coprocessor host */<a name="line.8422"></a>
-<span class="sourceLineNo">8423</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8423"></a>
-<span class="sourceLineNo">8424</span>    return coprocessorHost;<a name="line.8424"></a>
-<span class="sourceLineNo">8425</span>  }<a name="line.8425"></a>
-<span class="sourceLineNo">8426</span><a name="line.8426"></a>
-<span class="sourceLineNo">8427</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8427"></a>
-<span class="sourceLineNo">8428</span>  @VisibleForTesting<a name="line.8428"></a>
-<span class="sourceLineNo">8429</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8429"></a>
-<span class="sourceLineNo">8430</span>    this.coprocessorHost = coprocessorHost;<a name="line.8430"></a>
-<span class="sourceLineNo">8431</span>  }<a name="line.8431"></a>
-<span class="sourceLineNo">8432</span><a name="line.8432"></a>
-<span class="sourceLineNo">8433</span>  @Override<a name="line.8433"></a>
-<span class="sourceLineNo">8434</span>  public void startRegionOperation() throws IOException {<a name="line.8434"></a>
-<span class="sourceLineNo">8435</span>    startRegionOperation(Operation.ANY);<a name="line.8435"></a>
-<span class="sourceLineNo">8436</span>  }<a name="line.8436"></a>
-<span class="sourceLineNo">8437</span><a name="line.8437"></a>
-<span class="sourceLineNo">8438</span>  @Override<a name="line.8438"></a>
-<span class="sourceLineNo">8439</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8439"></a>
-<span class="sourceLineNo">8440</span>    switch (op) {<a name="line.8440"></a>
-<span class="sourceLineNo">8441</span>      case GET:  // read operations<a name="line.8441"></a>
-<span class="sourceLineNo">8442</span>      case SCAN:<a name="line.8442"></a>
-<span class="sourceLineNo">8443</span>        checkReadsEnabled();<a name="line.8443"></a>
-<span class="sourceLineNo">8444</span>        break;<a name="line.8444"></a>
-<span class="sourceLineNo">8445</span>      default:<a name="line.8445"></a>
-<span class="sourceLineNo">8446</span>        break;<a name="line.8446"></a>
-<span class="sourceLineNo">8447</span>    }<a name="line.8447"></a>
-<span class="sourceLineNo">8448</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8448"></a>
-<span class="sourceLineNo">8449</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8449"></a>
-<span class="sourceLineNo">8450</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8450"></a>
-<span class="sourceLineNo">8451</span>      // region<a name="line.8451"></a>
-<span class="sourceLineNo">8452</span>      return;<a name="line.8452"></a>
-<span class="sourceLineNo">8453</span>    }<a name="line.8453"></a>
-<span class="sourceLineNo">8454</span>    if (this.closing.get()) {<a name="line.8454"></a>
-<span class="sourceLineNo">8455</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8455"></a>
+<span class="sourceLineNo">8355</span>    return responseBuilder.build();<a name="line.8355"></a>
+<span class="sourceLineNo">8356</span>  }<a name="line.8356"></a>
+<span class="sourceLineNo">8357</span><a name="line.8357"></a>
+<span class="sourceLineNo">8358</span>  boolean shouldForceSplit() {<a name="line.8358"></a>
+<span class="sourceLineNo">8359</span>    return this.splitRequest;<a name="line.8359"></a>
+<span class="sourceLineNo">8360</span>  }<a name="line.8360"></a>
+<span class="sourceLineNo">8361</span><a name="line.8361"></a>
+<span class="sourceLineNo">8362</span>  byte[] getExplicitSplitPoint() {<a name="line.8362"></a>
+<span class="sourceLineNo">8363</span>    return this.explicitSplitPoint;<a name="line.8363"></a>
+<span class="sourceLineNo">8364</span>  }<a name="line.8364"></a>
+<span class="sourceLineNo">8365</span><a name="line.8365"></a>
+<span class="sourceLineNo">8366</span>  void forceSplit(byte[] sp) {<a name="line.8366"></a>
+<span class="sourceLineNo">8367</span>    // This HRegion will go away after the forced split is successful<a name="line.8367"></a>
+<span class="sourceLineNo">8368</span>    // But if a forced split fails, we need to clear forced split.<a name="line.8368"></a>
+<span class="sourceLineNo">8369</span>    this.splitRequest = true;<a name="line.8369"></a>
+<span class="sourceLineNo">8370</span>    if (sp != null) {<a name="line.8370"></a>
+<span class="sourceLineNo">8371</span>      this.explicitSplitPoint = sp;<a name="line.8371"></a>
+<span class="sourceLineNo">8372</span>    }<a name="line.8372"></a>
+<span class="sourceLineNo">8373</span>  }<a name="line.8373"></a>
+<span class="sourceLineNo">8374</span><a name="line.8374"></a>
+<span class="sourceLineNo">8375</span>  void clearSplit() {<a name="line.8375"></a>
+<span class="sourceLineNo">8376</span>    this.splitRequest = false;<a name="line.8376"></a>
+<span class="sourceLineNo">8377</span>    this.explicitSplitPoint = null;<a name="line.8377"></a>
+<span class="sourceLineNo">8378</span>  }<a name="line.8378"></a>
+<span class="sourceLineNo">8379</span><a name="line.8379"></a>
+<span class="sourceLineNo">8380</span>  /**<a name="line.8380"></a>
+<span class="sourceLineNo">8381</span>   * Return the splitpoint. null indicates the region isn't splittable<a name="line.8381"></a>
+<span class="sourceLineNo">8382</span>   * If the splitpoint isn't explicitly specified, it will go over the stores<a name="line.8382"></a>
+<span class="sourceLineNo">8383</span>   * to find the best splitpoint. Currently the criteria of best splitpoint<a name="line.8383"></a>
+<span class="sourceLineNo">8384</span>   * is based on the size of the store.<a name="line.8384"></a>
+<span class="sourceLineNo">8385</span>   */<a name="line.8385"></a>
+<span class="sourceLineNo">8386</span>  public byte[] checkSplit() {<a name="line.8386"></a>
+<span class="sourceLineNo">8387</span>    // Can't split META<a name="line.8387"></a>
+<span class="sourceLineNo">8388</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8388"></a>
+<span class="sourceLineNo">8389</span>      if (shouldForceSplit()) {<a name="line.8389"></a>
+<span class="sourceLineNo">8390</span>        LOG.warn("Cannot split meta region in HBase 0.20 and above");<a name="line.8390"></a>
+<span class="sourceLineNo">8391</span>      }<a name="line.8391"></a>
+<span class="sourceLineNo">8392</span>      return null;<a name="line.8392"></a>
+<span class="sourceLineNo">8393</span>    }<a name="line.8393"></a>
+<span class="sourceLineNo">8394</span><a name="line.8394"></a>
+<span class="sourceLineNo">8395</span>    // Can't split a region that is closing.<a name="line.8395"></a>
+<span class="sourceLineNo">8396</span>    if (this.isClosing()) {<a name="line.8396"></a>
+<span class="sourceLineNo">8397</span>      return null;<a name="line.8397"></a>
+<span class="sourceLineNo">8398</span>    }<a name="line.8398"></a>
+<span class="sourceLineNo">8399</span><a name="line.8399"></a>
+<span class="sourceLineNo">8400</span>    if (!splitPolicy.shouldSplit()) {<a name="line.8400"></a>
+<span class="sourceLineNo">8401</span>      return null;<a name="line.8401"></a>
+<span class="sourceLineNo">8402</span>    }<a name="line.8402"></a>
+<span class="sourceLineNo">8403</span><a name="line.8403"></a>
+<span class="sourceLineNo">8404</span>    byte[] ret = splitPolicy.getSplitPoint();<a name="line.8404"></a>
+<span class="sourceLineNo">8405</span><a name="line.8405"></a>
+<span class="sourceLineNo">8406</span>    if (ret != null) {<a name="line.8406"></a>
+<span class="sourceLineNo">8407</span>      try {<a name="line.8407"></a>
+<span class="sourceLineNo">8408</span>        checkRow(ret, "calculated split");<a name="line.8408"></a>
+<span class="sourceLineNo">8409</span>      } catch (IOException e) {<a name="line.8409"></a>
+<span class="sourceLineNo">8410</span>        LOG.error("Ignoring invalid split", e);<a name="line.8410"></a>
+<span class="sourceLineNo">8411</span>        return null;<a name="line.8411"></a>
+<span class="sourceLineNo">8412</span>      }<a name="line.8412"></a>
+<span class="sourceLineNo">8413</span>    }<a name="line.8413"></a>
+<span class="sourceLineNo">8414</span>    return ret;<a name="line.8414"></a>
+<span class="sourceLineNo">8415</span>  }<a name="line.8415"></a>
+<span class="sourceLineNo">8416</span><a name="line.8416"></a>
+<span class="sourceLineNo">8417</span>  /**<a name="line.8417"></a>
+<span class="sourceLineNo">8418</span>   * @return The priority that this region should have in the compaction queue<a name="line.8418"></a>
+<span class="sourceLineNo">8419</span>   */<a name="line.8419"></a>
+<span class="sourceLineNo">8420</span>  public int getCompactPriority() {<a name="line.8420"></a>
+<span class="sourceLineNo">8421</span>    return stores.values().stream().mapToInt(HStore::getCompactPriority).min()<a name="line.8421"></a>
+<span class="sourceLineNo">8422</span>        .orElse(Store.NO_PRIORITY);<a name="line.8422"></a>
+<span class="sourceLineNo">8423</span>  }<a name="line.8423"></a>
+<span class="sourceLineNo">8424</span><a name="line.8424"></a>
+<span class="sourceLineNo">8425</span>  /** @return the coprocessor host */<a name="line.8425"></a>
+<span class="sourceLineNo">8426</span>  public RegionCoprocessorHost getCoprocessorHost() {<a name="line.8426"></a>
+<span class="sourceLineNo">8427</span>    return coprocessorHost;<a name="line.8427"></a>
+<span class="sourceLineNo">8428</span>  }<a name="line.8428"></a>
+<span class="sourceLineNo">8429</span><a name="line.8429"></a>
+<span class="sourceLineNo">8430</span>  /** @param coprocessorHost the new coprocessor host */<a name="line.8430"></a>
+<span class="sourceLineNo">8431</span>  @VisibleForTesting<a name="line.8431"></a>
+<span class="sourceLineNo">8432</span>  public void setCoprocessorHost(final RegionCoprocessorHost coprocessorHost) {<a name="line.8432"></a>
+<span class="sourceLineNo">8433</span>    this.coprocessorHost = coprocessorHost;<a name="line.8433"></a>
+<span class="sourceLineNo">8434</span>  }<a name="line.8434"></a>
+<span class="sourceLineNo">8435</span><a name="line.8435"></a>
+<span class="sourceLineNo">8436</span>  @Override<a name="line.8436"></a>
+<span class="sourceLineNo">8437</span>  public void startRegionOperation() throws IOException {<a name="line.8437"></a>
+<span class="sourceLineNo">8438</span>    startRegionOperation(Operation.ANY);<a name="line.8438"></a>
+<span class="sourceLineNo">8439</span>  }<a name="line.8439"></a>
+<span class="sourceLineNo">8440</span><a name="line.8440"></a>
+<span class="sourceLineNo">8441</span>  @Override<a name="line.8441"></a>
+<span class="sourceLineNo">8442</span>  public void startRegionOperation(Operation op) throws IOException {<a name="line.8442"></a>
+<span class="sourceLineNo">8443</span>    switch (op) {<a name="line.8443"></a>
+<span class="sourceLineNo">8444</span>      case GET:  // read operations<a name="line.8444"></a>
+<span class="sourceLineNo">8445</span>      case SCAN:<a name="line.8445"></a>
+<span class="sourceLineNo">8446</span>        checkReadsEnabled();<a name="line.8446"></a>
+<span class="sourceLineNo">8447</span>        break;<a name="line.8447"></a>
+<span class="sourceLineNo">8448</span>      default:<a name="line.8448"></a>
+<span class="sourceLineNo">8449</span>        break;<a name="line.8449"></a>
+<span class="sourceLineNo">8450</span>    }<a name="line.8450"></a>
+<span class="sourceLineNo">8451</span>    if (op == Operation.MERGE_REGION || op == Operation.SPLIT_REGION<a name="line.8451"></a>
+<span class="sourceLineNo">8452</span>        || op == Operation.COMPACT_REGION || op == Operation.COMPACT_SWITCH) {<a name="line.8452"></a>
+<span class="sourceLineNo">8453</span>      // split, merge or compact region doesn't need to check the closing/closed state or lock the<a name="line.8453"></a>
+<span class="sourceLineNo">8454</span>      // region<a name="line.8454"></a>
+<span class="sourceLineNo">8455</span>      return;<a name="line.8455"></a>
 <span class="sourceLineNo">8456</span>    }<a name="line.8456"></a>
-<span class="sourceLineNo">8457</span>    lock(lock.readLock());<a name="line.8457"></a>
-<span class="sourceLineNo">8458</span>    if (this.closed.get()) {<a name="line.8458"></a>
-<span class="sourceLineNo">8459</span>      lock.readLock().unlock();<a name="line.8459"></a>
-<span class="sourceLineNo">8460</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8460"></a>
-<span class="sourceLineNo">8461</span>    }<a name="line.8461"></a>
-<span class="sourceLineNo">8462</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8462"></a>
-<span class="sourceLineNo">8463</span>    // prepared for snapshot operation before proceeding.<a name="line.8463"></a>
-<span class="sourceLineNo">8464</span>    if (op == Operation.SNAPSHOT) {<a name="line.8464"></a>
-<span class="sourceLineNo">8465</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8465"></a>
-<span class="sourceLineNo">8466</span>    }<a name="line.8466"></a>
-<span class="sourceLineNo">8467</span>    try {<a name="line.8467"></a>
-<span class="sourceLineNo">8468</span>      if (coprocessorHost != null) {<a name="line.8468"></a>
-<span class="sourceLineNo">8469</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8469"></a>
-<span class="sourceLineNo">8470</span>      }<a name="line.8470"></a>
-<span class="sourceLineNo">8471</span>    } catch (Exception e) {<a name="line.8471"></a>
-<span class="sourceLineNo">8472</span>      lock.readLock().unlock();<a name="line.8472"></a>
-<span class="sourceLineNo">8473</span>      throw new IOException(e);<a name="line.8473"></a>
-<span class="sourceLineNo">8474</span>    }<a name="line.8474"></a>
-<span class="sourceLineNo">8475</span>  }<a name="line.8475"></a>
-<span class="sourceLineNo">8476</span><a name="line.8476"></a>
-<span class="sourceLineNo">8477</span>  @Override<a name="line.8477"></a>
-<span class="sourceLineNo">8478</span>  public void closeRegionOperation() throws IOException {<a name="line.8478"></a>
-<span class="sourceLineNo">8479</span>    closeRegionOperation(Operation.ANY);<a name="line.8479"></a>
-<span class="sourceLineNo">8480</span>  }<a name="line.8480"></a>
-<span class="sourceLineNo">8481</span><a name="line.8481"></a>
-<span class="sourceLineNo">8482</span>  @Override<a name="line.8482"></a>
-<span class="sourceLineNo">8483</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8483"></a>
-<span class="sourceLineNo">8484</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8484"></a>
-<span class="sourceLineNo">8485</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8485"></a>
-<span class="sourceLineNo">8486</span>    }<a name="line.8486"></a>
-<span class="sourceLineNo">8487</span>    lock.readLock().unlock();<a name="line.8487"></a>
-<span class="sourceLineNo">8488</span>    if (coprocessorHost != null) {<a name="line.8488"></a>
-<span class="sourceLineNo">8489</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8489"></a>
-<span class="sourceLineNo">8490</span>    }<a name="line.8490"></a>
-<span class="sourceLineNo">8491</span>  }<a name="line.8491"></a>
-<span class="sourceLineNo">8492</span><a name="line.8492"></a>
-<span class="sourceLineNo">8493</span>  /**<a name="line.8493"></a>
-<span class="sourceLineNo">8494</span>   * This method needs to be called before any public call that reads or<a name="line.8494"></a>
-<span class="sourceLineNo">8495</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8495"></a>
-<span class="sourceLineNo">8496</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8496"></a>
-<span class="sourceLineNo">8497</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8497"></a>
-<span class="sourceLineNo">8498</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8498"></a>
-<span class="sourceLineNo">8499</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8499"></a>
-<span class="sourceLineNo">8500</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8500"></a>
-<span class="sourceLineNo">8501</span>   */<a name="line.8501"></a>
-<span class="sourceLineNo">8502</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8502"></a>
-<span class="sourceLineNo">8503</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8503"></a>
-<span class="sourceLineNo">8504</span>    if (this.closing.get()) {<a name="line.8504"></a>
-<span class="sourceLineNo">8505</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8505"></a>
-<span class="sourceLineNo">8506</span>    }<a name="line.8506"></a>
-<span class="sourceLineNo">8507</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8507"></a>
-<span class="sourceLineNo">8508</span>    else lock(lock.readLock());<a name="line.8508"></a>
-<span class="sourceLineNo">8509</span>    if (this.closed.get()) {<a name="line.8509"></a>
-<span class="sourceLineNo">8510</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8510"></a>
-<span class="sourceLineNo">8511</span>      else lock.readLock().unlock();<a name="line.8511"></a>
-<span class="sourceLineNo">8512</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8512"></a>
-<span class="sourceLineNo">8513</span>    }<a name="line.8513"></a>
-<span class="sourceLineNo">8514</span>  }<a name="line.8514"></a>
-<span class="sourceLineNo">8515</span><a name="line.8515"></a>
-<span class="sourceLineNo">8516</span>  /**<a name="line.8516"></a>
-<span class="sourceLineNo">8517</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8517"></a>
-<span class="sourceLineNo">8518</span>   * to the try block of #startRegionOperation<a name="line.8518"></a>
-<span class="sourceLineNo">8519</span>   */<a name="line.8519"></a>
-<span class="sourceLineNo">8520</span>  private void closeBulkRegionOperation(){<a name="line.8520"></a>
-<span class="sourceLineNo">8521</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8521"></a>
-<span class="sourceLineNo">8522</span>    else lock.readLock().unlock();<a name="line.8522"></a>
-<span class="sourceLineNo">8523</span>  }<a name="line.8523"></a>
-<span class="sourceLineNo">8524</span><a name="line.8524"></a>
-<span class="sourceLineNo">8525</span>  /**<a name="line.8525"></a>
-<span class="sourceLineNo">8526</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8526"></a>
-<span class="sourceLineNo">8527</span>   * These information are exposed by the region server metrics.<a name="line.8527"></a>
-<span class="sourceLineNo">8528</span>   */<a name="line.8528"></a>
-<span class="sourceLineNo">8529</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8529"></a>
-<span class="sourceLineNo">8530</span>    numMutationsWithoutWAL.increment();<a name="line.8530"></a>
-<span class="sourceLineNo">8531</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8531"></a>
-<span class="sourceLineNo">8532</span>      LOG.info("writing data to region " + this +<a name="line.8532"></a>
-<span class="sourceLineNo">8533</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8533"></a>
-<span class="sourceLineNo">8534</span>    }<a name="line.8534"></a>
-<span class="sourceLineNo">8535</span><a name="line.8535"></a>
-<span class="sourceLineNo">8536</span>    long mutationSize = 0;<a name="line.8536"></a>
-<span class="sourceLineNo">8537</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8537"></a>
-<span class="sourceLineNo">8538</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8538"></a>
-<span class="sourceLineNo">8539</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8539"></a>
-<span class="sourceLineNo">8540</span>      assert cells instanceof RandomAccess;<a name="line.8540"></a>
-<span class="sourceLineNo">8541</span>      int listSize = cells.size();<a name="line.8541"></a>
-<span class="sourceLineNo">8542</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8542"></a>
-<span class="sourceLineNo">8543</span>        Cell cell = cells.get(i);<a name="line.8543"></a>
-<span class="sourceLineNo">8544</span>        mutationSize += cell.getSerializedSize();<a name="line.8544"></a>
-<span class="sourceLineNo">8545</span>      }<a name="line.8545"></a>
-<span class="sourceLineNo">8546</span>    }<a name="line.8546"></a>
-<span class="sourceLineNo">8547</span><a name="line.8547"></a>
-<span class="sourceLineNo">8548</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8548"></a>
-<span class="sourceLineNo">8549</span>  }<a name="line.8549"></a>
+<span class="sourceLineNo">8457</span>    if (this.closing.get()) {<a name="line.8457"></a>
+<span class="sourceLineNo">8458</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8458"></a>
+<span class="sourceLineNo">8459</span>    }<a name="line.8459"></a>
+<span class="sourceLineNo">8460</span>    lock(lock.readLock());<a name="line.8460"></a>
+<span class="sourceLineNo">8461</span>    if (this.closed.get()) {<a name="line.8461"></a>
+<span class="sourceLineNo">8462</span>      lock.readLock().unlock();<a name="line.8462"></a>
+<span class="sourceLineNo">8463</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8463"></a>
+<span class="sourceLineNo">8464</span>    }<a name="line.8464"></a>
+<span class="sourceLineNo">8465</span>    // The unit for snapshot is a region. So, all stores for this region must be<a name="line.8465"></a>
+<span class="sourceLineNo">8466</span>    // prepared for snapshot operation before proceeding.<a name="line.8466"></a>
+<span class="sourceLineNo">8467</span>    if (op == Operation.SNAPSHOT) {<a name="line.8467"></a>
+<span class="sourceLineNo">8468</span>      stores.values().forEach(HStore::preSnapshotOperation);<a name="line.8468"></a>
+<span class="sourceLineNo">8469</span>    }<a name="line.8469"></a>
+<span class="sourceLineNo">8470</span>    try {<a name="line.8470"></a>
+<span class="sourceLineNo">8471</span>      if (coprocessorHost != null) {<a name="line.8471"></a>
+<span class="sourceLineNo">8472</span>        coprocessorHost.postStartRegionOperation(op);<a name="line.8472"></a>
+<span class="sourceLineNo">8473</span>      }<a name="line.8473"></a>
+<span class="sourceLineNo">8474</span>    } catch (Exception e) {<a name="line.8474"></a>
+<span class="sourceLineNo">8475</span>      lock.readLock().unlock();<a name="line.8475"></a>
+<span class="sourceLineNo">8476</span>      throw new IOException(e);<a name="line.8476"></a>
+<span class="sourceLineNo">8477</span>    }<a name="line.8477"></a>
+<span class="sourceLineNo">8478</span>  }<a name="line.8478"></a>
+<span class="sourceLineNo">8479</span><a name="line.8479"></a>
+<span class="sourceLineNo">8480</span>  @Override<a name="line.8480"></a>
+<span class="sourceLineNo">8481</span>  public void closeRegionOperation() throws IOException {<a name="line.8481"></a>
+<span class="sourceLineNo">8482</span>    closeRegionOperation(Operation.ANY);<a name="line.8482"></a>
+<span class="sourceLineNo">8483</span>  }<a name="line.8483"></a>
+<span class="sourceLineNo">8484</span><a name="line.8484"></a>
+<span class="sourceLineNo">8485</span>  @Override<a name="line.8485"></a>
+<span class="sourceLineNo">8486</span>  public void closeRegionOperation(Operation operation) throws IOException {<a name="line.8486"></a>
+<span class="sourceLineNo">8487</span>    if (operation == Operation.SNAPSHOT) {<a name="line.8487"></a>
+<span class="sourceLineNo">8488</span>      stores.values().forEach(HStore::postSnapshotOperation);<a name="line.8488"></a>
+<span class="sourceLineNo">8489</span>    }<a name="line.8489"></a>
+<span class="sourceLineNo">8490</span>    lock.readLock().unlock();<a name="line.8490"></a>
+<span class="sourceLineNo">8491</span>    if (coprocessorHost != null) {<a name="line.8491"></a>
+<span class="sourceLineNo">8492</span>      coprocessorHost.postCloseRegionOperation(operation);<a name="line.8492"></a>
+<span class="sourceLineNo">8493</span>    }<a name="line.8493"></a>
+<span class="sourceLineNo">8494</span>  }<a name="line.8494"></a>
+<span class="sourceLineNo">8495</span><a name="line.8495"></a>
+<span class="sourceLineNo">8496</span>  /**<a name="line.8496"></a>
+<span class="sourceLineNo">8497</span>   * This method needs to be called before any public call that reads or<a name="line.8497"></a>
+<span class="sourceLineNo">8498</span>   * modifies stores in bulk. It has to be called just before a try.<a name="line.8498"></a>
+<span class="sourceLineNo">8499</span>   * #closeBulkRegionOperation needs to be called in the try's finally block<a name="line.8499"></a>
+<span class="sourceLineNo">8500</span>   * Acquires a writelock and checks if the region is closing or closed.<a name="line.8500"></a>
+<span class="sourceLineNo">8501</span>   * @throws NotServingRegionException when the region is closing or closed<a name="line.8501"></a>
+<span class="sourceLineNo">8502</span>   * @throws RegionTooBusyException if failed to get the lock in time<a name="line.8502"></a>
+<span class="sourceLineNo">8503</span>   * @throws InterruptedIOException if interrupted while waiting for a lock<a name="line.8503"></a>
+<span class="sourceLineNo">8504</span>   */<a name="line.8504"></a>
+<span class="sourceLineNo">8505</span>  private void startBulkRegionOperation(boolean writeLockNeeded)<a name="line.8505"></a>
+<span class="sourceLineNo">8506</span>      throws NotServingRegionException, RegionTooBusyException, InterruptedIOException {<a name="line.8506"></a>
+<span class="sourceLineNo">8507</span>    if (this.closing.get()) {<a name="line.8507"></a>
+<span class="sourceLineNo">8508</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closing");<a name="line.8508"></a>
+<span class="sourceLineNo">8509</span>    }<a name="line.8509"></a>
+<span class="sourceLineNo">8510</span>    if (writeLockNeeded) lock(lock.writeLock());<a name="line.8510"></a>
+<span class="sourceLineNo">8511</span>    else lock(lock.readLock());<a name="line.8511"></a>
+<span class="sourceLineNo">8512</span>    if (this.closed.get()) {<a name="line.8512"></a>
+<span class="sourceLineNo">8513</span>      if (writeLockNeeded) lock.writeLock().unlock();<a name="line.8513"></a>
+<span class="sourceLineNo">8514</span>      else lock.readLock().unlock();<a name="line.8514"></a>
+<span class="sourceLineNo">8515</span>      throw new NotServingRegionException(getRegionInfo().getRegionNameAsString() + " is closed");<a name="line.8515"></a>
+<span class="sourceLineNo">8516</span>    }<a name="line.8516"></a>
+<span class="sourceLineNo">8517</span>  }<a name="line.8517"></a>
+<span class="sourceLineNo">8518</span><a name="line.8518"></a>
+<span class="sourceLineNo">8519</span>  /**<a name="line.8519"></a>
+<span class="sourceLineNo">8520</span>   * Closes the lock. This needs to be called in the finally block corresponding<a name="line.8520"></a>
+<span class="sourceLineNo">8521</span>   * to the try block of #startRegionOperation<a name="line.8521"></a>
+<span class="sourceLineNo">8522</span>   */<a name="line.8522"></a>
+<span class="sourceLineNo">8523</span>  private void closeBulkRegionOperation(){<a name="line.8523"></a>
+<span class="sourceLineNo">8524</span>    if (lock.writeLock().isHeldByCurrentThread()) lock.writeLock().unlock();<a name="line.8524"></a>
+<span class="sourceLineNo">8525</span>    else lock.readLock().unlock();<a name="line.8525"></a>
+<span class="sourceLineNo">8526</span>  }<a name="line.8526"></a>
+<span class="sourceLineNo">8527</span><a name="line.8527"></a>
+<span class="sourceLineNo">8528</span>  /**<a name="line.8528"></a>
+<span class="sourceLineNo">8529</span>   * Update LongAdders for number of puts without wal and the size of possible data loss.<a name="line.8529"></a>
+<span class="sourceLineNo">8530</span>   * These information are exposed by the region server metrics.<a name="line.8530"></a>
+<span class="sourceLineNo">8531</span>   */<a name="line.8531"></a>
+<span class="sourceLineNo">8532</span>  private void recordMutationWithoutWal(final Map&lt;byte [], List&lt;Cell&gt;&gt; familyMap) {<a name="line.8532"></a>
+<span class="sourceLineNo">8533</span>    numMutationsWithoutWAL.increment();<a name="line.8533"></a>
+<span class="sourceLineNo">8534</span>    if (numMutationsWithoutWAL.sum() &lt;= 1) {<a name="line.8534"></a>
+<span class="sourceLineNo">8535</span>      LOG.info("writing data to region " + this +<a name="line.8535"></a>
+<span class="sourceLineNo">8536</span>               " with WAL disabled. Data may be lost in the event of a crash.");<a name="line.8536"></a>
+<span class="sourceLineNo">8537</span>    }<a name="line.8537"></a>
+<span class="sourceLineNo">8538</span><a name="line.8538"></a>
+<span class="sourceLineNo">8539</span>    long mutationSize = 0;<a name="line.8539"></a>
+<span class="sourceLineNo">8540</span>    for (List&lt;Cell&gt; cells: familyMap.values()) {<a name="line.8540"></a>
+<span class="sourceLineNo">8541</span>      // Optimization: 'foreach' loop is not used. See:<a name="line.8541"></a>
+<span class="sourceLineNo">8542</span>      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects<a name="line.8542"></a>
+<span class="sourceLineNo">8543</span>      assert cells instanceof RandomAccess;<a name="line.8543"></a>
+<span class="sourceLineNo">8544</span>      int listSize = cells.size();<a name="line.8544"></a>
+<span class="sourceLineNo">8545</span>      for (int i=0; i &lt; listSize; i++) {<a name="line.8545"></a>
+<span class="sourceLineNo">8546</span>        Cell cell = cells.get(i);<a name="line.8546"></a>
+<span class="sourceLineNo">8547</span>        mutationSize += cell.getSerializedSize();<a name="line.8547"></a>
+<span class="sourceLineNo">8548</span>      }<a name="line.8548"></a>
+<span class="sourceLineNo">8549</span>    }<a name="line.8549"></a>
 <span class="sourceLineNo">8550</span><a name="line.8550"></a>
-<span class="sourceLineNo">8551</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8551"></a>
-<span class="sourceLineNo">8552</span>    lock(lock, 1);<a name="line.8552"></a>
-<span class="sourceLineNo">8553</span>  }<a name="line.8553"></a>
-<span class="sourceLineNo">8554</span><a name="line.8554"></a>
-<span class="sourceLineNo">8555</span>  /**<a name="line.8555"></a>
-<span class="sourceLineNo">8556</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8556"></a>
-<span class="sourceLineNo">8557</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8557"></a>
-<span class="sourceLineNo">8558</span>   * if interrupted while waiting for the lock.<a name="line.8558"></a>
-<span class="sourceLineNo">8559</span>   */<a name="line.8559"></a>
-<span class="sourceLineNo">8560</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8560"></a>
-<span class="sourceLineNo">8561</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8561"></a>
-<span class="sourceLineNo">8562</span>    try {<a name="line.8562"></a>
-<span class="sourceLineNo">8563</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8563"></a>
-<span class="sourceLineNo">8564</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8564"></a>
-<span class="sourceLineNo">8565</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8565"></a>
-<span class="sourceLineNo">8566</span>        // Don't print millis. Message is used as a key over in<a name="line.8566"></a>
-<span class="sourceLineNo">8567</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8567"></a>
-<span class="sourceLineNo">8568</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8568"></a>
-<span class="sourceLineNo">8569</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8569"></a>
-<span class="sourceLineNo">8570</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8570"></a>
-<span class="sourceLineNo">8571</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8571"></a>
-<span class="sourceLineNo">8572</span>                this.getRegionServerServices().getServerName()));<a name="line.8572"></a>
-<span class="sourceLineNo">8573</span>      }<a name="line.8573"></a>
-<span class="sourceLineNo">8574</span>    } catch (InterruptedException ie) {<a name="line.8574"></a>
-<span class="sourceLineNo">8575</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8575"></a>
-<span class="sourceLineNo">8576</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8576"></a>
-<span class="sourceLineNo">8577</span>      iie.initCause(ie);<a name="line.8577"></a>
-<span class="sourceLineNo">8578</span>      throw iie;<a name="line.8578"></a>
-<span class="sourceLineNo">8579</span>    }<a name="line.8579"></a>
-<span class="sourceLineNo">8580</span>  }<a name="line.8580"></a>
-<span class="sourceLineNo">8581</span><a name="line.8581"></a>
-<span class="sourceLineNo">8582</span>  /**<a name="line.8582"></a>
-<span class="sourceLineNo">8583</span>   * Calls sync with the given transaction ID<a name="line.8583"></a>
-<span class="sourceLineNo">8584</span>   * @param txid should sync up to which transaction<a name="line.8584"></a>
-<span class="sourceLineNo">8585</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8585"></a>
-<span class="sourceLineNo">8586</span>   */<a name="line.8586"></a>
-<span class="sourceLineNo">8587</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8587"></a>
-<span class="sourceLineNo">8588</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8588"></a>
-<span class="sourceLineNo">8589</span>      this.wal.sync(txid);<a name="line.8589"></a>
-<span class="sourceLineNo">8590</span>    } else {<a name="line.8590"></a>
-<span class="sourceLineNo">8591</span>      switch(durability) {<a name="line.8591"></a>
-<span class="sourceLineNo">8592</span>      case USE_DEFAULT:<a name="line.8592"></a>
-<span class="sourceLineNo">8593</span>        // do what table defaults to<a name="line.8593"></a>
-<span class="sourceLineNo">8594</span>        if (shouldSyncWAL()) {<a name="line.8594"></a>
-<span class="sourceLineNo">8595</span>          this.wal.sync(txid);<a name="line.8595"></a>
-<span class="sourceLineNo">8596</span>        }<a name="line.8596"></a>
-<span class="sourceLineNo">8597</span>        break;<a name="line.8597"></a>
-<span class="sourceLineNo">8598</span>      case SKIP_WAL:<a name="line.8598"></a>
-<span class="sourceLineNo">8599</span>        // nothing do to<a name="line.8599"></a>
+<span class="sourceLineNo">8551</span>    dataInMemoryWithoutWAL.add(mutationSize);<a name="line.8551"></a>
+<span class="sourceLineNo">8552</span>  }<a name="line.8552"></a>
+<span class="sourceLineNo">8553</span><a name="line.8553"></a>
+<span class="sourceLineNo">8554</span>  private void lock(final Lock lock) throws RegionTooBusyException, InterruptedIOException {<a name="line.8554"></a>
+<span class="sourceLineNo">8555</span>    lock(lock, 1);<a name="line.8555"></a>
+<span class="sourceLineNo">8556</span>  }<a name="line.8556"></a>
+<span class="sourceLineNo">8557</span><a name="line.8557"></a>
+<span class="sourceLineNo">8558</span>  /**<a name="line.8558"></a>
+<span class="sourceLineNo">8559</span>   * Try to acquire a lock.  Throw RegionTooBusyException<a name="line.8559"></a>
+<span class="sourceLineNo">8560</span>   * if failed to get the lock in time. Throw InterruptedIOException<a name="line.8560"></a>
+<span class="sourceLineNo">8561</span>   * if interrupted while waiting for the lock.<a name="line.8561"></a>
+<span class="sourceLineNo">8562</span>   */<a name="line.8562"></a>
+<span class="sourceLineNo">8563</span>  private void lock(final Lock lock, final int multiplier)<a name="line.8563"></a>
+<span class="sourceLineNo">8564</span>      throws RegionTooBusyException, InterruptedIOException {<a name="line.8564"></a>
+<span class="sourceLineNo">8565</span>    try {<a name="line.8565"></a>
+<span class="sourceLineNo">8566</span>      final long waitTime = Math.min(maxBusyWaitDuration,<a name="line.8566"></a>
+<span class="sourceLineNo">8567</span>          busyWaitDuration * Math.min(multiplier, maxBusyWaitMultiplier));<a name="line.8567"></a>
+<span class="sourceLineNo">8568</span>      if (!lock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {<a name="line.8568"></a>
+<span class="sourceLineNo">8569</span>        // Don't print millis. Message is used as a key over in<a name="line.8569"></a>
+<span class="sourceLineNo">8570</span>        // RetriesExhaustedWithDetailsException processing.<a name="line.8570"></a>
+<span class="sourceLineNo">8571</span>        throw new RegionTooBusyException("Failed to obtain lock; regionName=" +<a name="line.8571"></a>
+<span class="sourceLineNo">8572</span>            (this.getRegionInfo() == null? "unknown":<a name="line.8572"></a>
+<span class="sourceLineNo">8573</span>                this.getRegionInfo().getRegionNameAsString()) +<a name="line.8573"></a>
+<span class="sourceLineNo">8574</span>            ", server=" + (this.getRegionServerServices() == null? "unknown":<a name="line.8574"></a>
+<span class="sourceLineNo">8575</span>                this.getRegionServerServices().getServerName()));<a name="line.8575"></a>
+<span class="sourceLineNo">8576</span>      }<a name="line.8576"></a>
+<span class="sourceLineNo">8577</span>    } catch (InterruptedException ie) {<a name="line.8577"></a>
+<span class="sourceLineNo">8578</span>      LOG.info("Interrupted while waiting for a lock");<a name="line.8578"></a>
+<span class="sourceLineNo">8579</span>      InterruptedIOException iie = new InterruptedIOException();<a name="line.8579"></a>
+<span class="sourceLineNo">8580</span>      iie.initCause(ie);<a name="line.8580"></a>
+<span class="sourceLineNo">8581</span>      throw iie;<a name="line.8581"></a>
+<span class="sourceLineNo">8582</span>    }<a name="line.8582"></a>
+<span class="sourceLineNo">8583</span>  }<a name="line.8583"></a>
+<span class="sourceLineNo">8584</span><a name="line.8584"></a>
+<span class="sourceLineNo">8585</span>  /**<a name="line.8585"></a>
+<span class="sourceLineNo">8586</span>   * Calls sync with the given transaction ID<a name="line.8586"></a>
+<span class="sourceLineNo">8587</span>   * @param txid should sync up to which transaction<a name="line.8587"></a>
+<span class="sourceLineNo">8588</span>   * @throws IOException If anything goes wrong with DFS<a name="line.8588"></a>
+<span class="sourceLineNo">8589</span>   */<a name="line.8589"></a>
+<span class="sourceLineNo">8590</span>  private void sync(long txid, Durability durability) throws IOException {<a name="line.8590"></a>
+<span class="sourceLineNo">8591</span>    if (this.getRegionInfo().isMetaRegion()) {<a name="line.8591"></a>
+<span class="sourceLineNo">8592</span>      this.wal.sync(txid);<a name="line.8592"></a>
+<span class="sourceLineNo">8593</span>    } else {<a name="line.8593"></a>
+<span class="sourceLineNo">8594</span>      switch(durability) {<a name="line.8594"></a>
+<span class="sourceLineNo">8595</span>      case USE_DEFAULT:<a name="line.8595"></a>
+<span class="sourceLineNo">8596</span>        // do what table defaults to<a name="line.8596"></a>
+<span class="sourceLineNo">8597</span>        if (shouldSyncWAL()) {<a name="line.8597"></a>
+<span class="sourceLineNo">8598</span>          this.wal.sync(txid);<a name="line.8598"></a>
+<span class="sourceLineNo">8599</span>        }<a name="line.8599"></a>
 <span class="sourceLineNo">8600</span>        break;<a name="line.8600"></a>
-<span class="sourceLineNo">8601</span>      case ASYNC_WAL:<a name="line.8601"></a>
+<span class="sourceLineNo">8601</span>      case SKIP_WAL:<a name="line.8601"></a>
 <span class="sourceLineNo">8602</span>        // nothing do to<a name="line.8602"></a>
 <span class="sourceLineNo">8603</span>        break;<a name="line.8603"></a>
-<span class="sourceLineNo">8604</span>      case SYNC_WAL:<a name="line.8604"></a>
-<span class="sourceLineNo">8605</span>          this.wal.sync(txid, false);<a name="line.8605"></a>
-<span class="sourceLineNo">8606</span>          break;<a name="line.8606"></a>
-<span class="sourceLineNo">8607</span>      case FSYNC_WAL:<a name="line.8607"></a>
-<span class="sourceLineNo">8608</span>          this.wal.sync(txid, true);<a name="line.8608"></a>
+<span class="sourceLineNo">8604</span>      case ASYNC_WAL:<a name="line.8604"></a>
+<span class="sourceLineNo">8605</span>        // nothing do to<a name="line.8605"></a>
+<span class="sourceLineNo">8606</span>        break;<a name="line.8606"></a>
+<span class="sourceLineNo">8607</span>      case SYNC_WAL:<a name="line.8607"></a>
+<span class="sourceLineNo">8608</span>          this.wal.sync(txid, false);<a name="line.8608"></a>
 <span class="sourceLineNo">8609</span>          break;<a name="line.8609"></a>
-<span class="sourceLineNo">8610</span>      default:<a name="line.8610"></a>
-<span class="sourceLineNo">8611</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8611"></a>
-<span class="sourceLineNo">8612</span>      }<a name="line.8612"></a>
-<span class="sourceLineNo">8613</span>    }<a name="line.8613"></a>
-<span class="sourceLineNo">8614</span>  }<a name="line.8614"></a>
-<span class="sourceLineNo">8615</span><a name="line.8615"></a>
-<span class="sourceLineNo">8616</span>  /**<a name="line.8616"></a>
-<span class="sourceLineNo">8617</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8617"></a>
-<span class="sourceLineNo">8618</span>   */<a name="line.8618"></a>
-<span class="sourceLineNo">8619</span>  private boolean shouldSyncWAL() {<a name="line.8619"></a>
-<span class="sourceLineNo">8620</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8620"></a>
-<span class="sourceLineNo">8621</span>  }<a name="line.8621"></a>
-<span class="sourceLineNo">8622</span><a name="line.8622"></a>
-<span class="sourceLineNo">8623</span>  /**<a name="line.8623"></a>
-<span class="sourceLineNo">8624</span>   * A mocked list implementation - discards all updates.<a name="line.8624"></a>
-<span class="sourceLineNo">8625</span>   */<a name="line.8625"></a>
-<span class="sourceLineNo">8626</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8626"></a>
-<span class="sourceLineNo">8627</span><a name="line.8627"></a>
-<span class="sourceLineNo">8628</span>    @Override<a name="line.8628"></a>
-<span class="sourceLineNo">8629</span>    public void add(int index, Cell element) {<a name="line.8629"></a>
-<span class="sourceLineNo">8630</span>      // do nothing<a name="line.8630"></a>
-<span class="sourceLineNo">8631</span>    }<a name="line.8631"></a>
-<span class="sourceLineNo">8632</span><a name="line.8632"></a>
-<span class="sourceLineNo">8633</span>    @Override<a name="line.8633"></a>
-<span class="sourceLineNo">8634</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8634"></a>
-<span class="sourceLineNo">8635</span>      return false; // this list is never changed as a result of an update<a name="line.8635"></a>
-<span class="sourceLineNo">8636</span>    }<a name="line.8636"></a>
-<span class="sourceLineNo">8637</span><a name="line.8637"></a>
-<span class="sourceLineNo">8638</span>    @Override<a name="line.8638"></a>
-<span class="sourceLineNo">8639</span>    public KeyValue get(int index) {<a name="line.8639"></a>
-<span class="sourceLineNo">8640</span>      throw new UnsupportedOperationException();<a name="line.8640"></a>
-<span class="sourceLineNo">8641</span>    }<a name="line.8641"></a>
-<span class="sourceLineNo">8642</span><a name="line.8642"></a>
-<span class="sourceLineNo">8643</span>    @Override<a name="line.8643"></a>
-<span class="sourceLineNo">8644</span>    public int size() {<a name="line.8644"></a>
-<span class="sourceLineNo">8645</span>      return 0;<a name="line.8645"></a>
-<span class="sourceLineNo">8646</span>    }<a name="line.8646"></a>
-<span class="sourceLineNo">8647</span>  };<a name="line.8647"></a>
-<span class="sourceLineNo">8648</span><a name="line.8648"></a>
-<span class="sourceLineNo">8649</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8649"></a>
-<span class="sourceLineNo">8650</span>  public long getOpenSeqNum() {<a name="line.8650"></a>
-<span class="sourceLineNo">8651</span>    return this.openSeqNum;<a name="line.8651"></a>
-<span class="sourceLineNo">8652</span>  }<a name="line.8652"></a>
-<span class="sourceLineNo">8653</span><a name="line.8653"></a>
-<span class="sourceLineNo">8654</span>  @Override<a name="line.8654"></a>
-<span class="sourceLineNo">8655</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8655"></a>
-<span class="sourceLineNo">8656</span>    return this.maxSeqIdInStores;<a name="line.8656"></a>
-<span class="sourceLineNo">8657</span>  }<a name="line.8657"></a>
-<span class="sourceLineNo">8658</span><a name="line.8658"></a>
-<span class="sourceLineNo">8659</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8659"></a>
-<span class="sourceLineNo">8660</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8660"></a>
-<span class="sourceLineNo">8661</span>  }<a name="line.8661"></a>
-<span class="sourceLineNo">8662</span><a name="line.8662"></a>
-<span class="sourceLineNo">8663</span>  @Override<a name="line.8663"></a>
-<span class="sourceLineNo">8664</span>  public CompactionState getCompactionState() {<a name="line.8664"></a>
-<span class="sourceLineNo">8665</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8665"></a>
-<span class="sourceLineNo">8666</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8666"></a>
-<span class="sourceLineNo">8667</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8667"></a>
-<span class="sourceLineNo">8668</span>  }<a name="line.8668"></a>
-<span class="sourceLineNo">8669</span><a name="line.8669"></a>
-<span class="sourceLineNo">8670</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8670"></a>
-<span class="sourceLineNo">8671</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8671"></a>
-<span class="sourceLineNo">8672</span>  }<a name="line.8672"></a>
-<span class="sourceLineNo">8673</span><a name="line.8673"></a>
-<span class="sourceLineNo">8674</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8674"></a>
-<span class="sourceLineNo">8675</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8675"></a>
+<span class="sourceLineNo">8610</span>      case FSYNC_WAL:<a name="line.8610"></a>
+<span class="sourceLineNo">8611</span>          this.wal.sync(txid, true);<a name="line.8611"></a>
+<span class="sourceLineNo">8612</span>          break;<a name="line.8612"></a>
+<span class="sourceLineNo">8613</span>      default:<a name="line.8613"></a>
+<span class="sourceLineNo">8614</span>        throw new RuntimeException("Unknown durability " + durability);<a name="line.8614"></a>
+<span class="sourceLineNo">8615</span>      }<a name="line.8615"></a>
+<span class="sourceLineNo">8616</span>    }<a name="line.8616"></a>
+<span class="sourceLineNo">8617</span>  }<a name="line.8617"></a>
+<span class="sourceLineNo">8618</span><a name="line.8618"></a>
+<span class="sourceLineNo">8619</span>  /**<a name="line.8619"></a>
+<span class="sourceLineNo">8620</span>   * Check whether we should sync the wal from the table's durability settings<a name="line.8620"></a>
+<span class="sourceLineNo">8621</span>   */<a name="line.8621"></a>
+<span class="sourceLineNo">8622</span>  private boolean shouldSyncWAL() {<a name="line.8622"></a>
+<span class="sourceLineNo">8623</span>    return regionDurability.ordinal() &gt;  Durability.ASYNC_WAL.ordinal();<a name="line.8623"></a>
+<span class="sourceLineNo">8624</span>  }<a name="line.8624"></a>
+<span class="sourceLineNo">8625</span><a name="line.8625"></a>
+<span class="sourceLineNo">8626</span>  /**<a name="line.8626"></a>
+<span class="sourceLineNo">8627</span>   * A mocked list implementation - discards all updates.<a name="line.8627"></a>
+<span class="sourceLineNo">8628</span>   */<a name="line.8628"></a>
+<span class="sourceLineNo">8629</span>  private static final List&lt;Cell&gt; MOCKED_LIST = new AbstractList&lt;Cell&gt;() {<a name="line.8629"></a>
+<span class="sourceLineNo">8630</span><a name="line.8630"></a>
+<span class="sourceLineNo">8631</span>    @Override<a name="line.8631"></a>
+<span class="sourceLineNo">8632</span>    public void add(int index, Cell element) {<a name="line.8632"></a>
+<span class="sourceLineNo">8633</span>      // do nothing<a name="line.8633"></a>
+<span class="sourceLineNo">8634</span>    }<a name="line.8634"></a>
+<span class="sourceLineNo">8635</span><a name="line.8635"></a>
+<span class="sourceLineNo">8636</span>    @Override<a name="line.8636"></a>
+<span class="sourceLineNo">8637</span>    public boolean addAll(int index, Collection&lt;? extends Cell&gt; c) {<a name="line.8637"></a>
+<span class="sourceLineNo">8638</span>      return false; // this list is never changed as a result of an update<a name="line.8638"></a>
+<span class="sourceLineNo">8639</span>    }<a name="line.8639"></a>
+<span class="sourceLineNo">8640</span><a name="line.8640"></a>
+<span class="sourceLineNo">8641</span>    @Override<a name="line.8641"></a>
+<span class="sourceLineNo">8642</span>    public KeyValue get(int index) {<a name="line.8642"></a>
+<span class="sourceLineNo">8643</span>      throw new UnsupportedOperationException();<a name="line.8643"></a>
+<span class="sourceLineNo">8644</span>    }<a name="line.8644"></a>
+<span class="sourceLineNo">8645</span><a name="line.8645"></a>
+<span class="sourceLineNo">8646</span>    @Override<a name="line.8646"></a>
+<span class="sourceLineNo">8647</span>    public int size() {<a name="line.8647"></a>
+<span class="sourceLineNo">8648</span>      return 0;<a name="line.8648"></a>
+<span class="sourceLineNo">8649</span>    }<a name="line.8649"></a>
+<span class="sourceLineNo">8650</span>  };<a name="line.8650"></a>
+<span class="sourceLineNo">8651</span><a name="line.8651"></a>
+<span class="sourceLineNo">8652</span>  /** @return the latest sequence number that was read from storage when this region was opened */<a name="line.8652"></a>
+<span class="sourceLineNo">8653</span>  public long getOpenSeqNum() {<a name="line.8653"></a>
+<span class="sourceLineNo">8654</span>    return this.openSeqNum;<a name="line.8654"></a>
+<span class="sourceLineNo">8655</span>  }<a name="line.8655"></a>
+<span class="sourceLineNo">8656</span><a name="line.8656"></a>
+<span class="sourceLineNo">8657</span>  @Override<a name="line.8657"></a>
+<span class="sourceLineNo">8658</span>  public Map&lt;byte[], Long&gt; getMaxStoreSeqId() {<a name="line.8658"></a>
+<span class="sourceLineNo">8659</span>    return this.maxSeqIdInStores;<a name="line.8659"></a>
+<span class="sourceLineNo">8660</span>  }<a name="line.8660"></a>
+<span class="sourceLineNo">8661</span><a name="line.8661"></a>
+<span class="sourceLineNo">8662</span>  public long getOldestSeqIdOfStore(byte[] familyName) {<a name="line.8662"></a>
+<span class="sourceLineNo">8663</span>    return wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(), familyName);<a name="line.8663"></a>
+<span class="sourceLineNo">8664</span>  }<a name="line.8664"></a>
+<span class="sourceLineNo">8665</span><a name="line.8665"></a>
+<span class="sourceLineNo">8666</span>  @Override<a name="line.8666"></a>
+<span class="sourceLineNo">8667</span>  public CompactionState getCompactionState() {<a name="line.8667"></a>
+<span class="sourceLineNo">8668</span>    boolean hasMajor = majorInProgress.get() &gt; 0, hasMinor = minorInProgress.get() &gt; 0;<a name="line.8668"></a>
+<span class="sourceLineNo">8669</span>    return (hasMajor ? (hasMinor ? CompactionState.MAJOR_AND_MINOR : CompactionState.MAJOR)<a name="line.8669"></a>
+<span class="sourceLineNo">8670</span>        : (hasMinor ? CompactionState.MINOR : CompactionState.NONE));<a name="line.8670"></a>
+<span class="sourceLineNo">8671</span>  }<a name="line.8671"></a>
+<span class="sourceLineNo">8672</span><a name="line.8672"></a>
+<span class="sourceLineNo">8673</span>  public void reportCompactionRequestStart(boolean isMajor){<a name="line.8673"></a>
+<span class="sourceLineNo">8674</span>    (isMajor ? majorInProgress : minorInProgress).incrementAndGet();<a name="line.8674"></a>
+<span class="sourceLineNo">8675</span>  }<a name="line.8675"></a>
 <span class="sourceLineNo">8676</span><a name="line.8676"></a>
-<span class="sourceLineNo">8677</span>    // metrics<a name="line.8677"></a>
-<span class="sourceLineNo">8678</span>    compactionsFinished.increment();<a name="line.8678"></a>
-<span class="sourceLineNo">8679</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8679"></a>
-<span class="sourceLineNo">8680</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8680"></a>
-<span class="sourceLineNo">8681</span><a name="line.8681"></a>
-<span class="sourceLineNo">8682</span>    assert newValue &gt;= 0;<a name="line.8682"></a>
-<span class="sourceLineNo">8683</span>  }<a name="line.8683"></a>
+<span class="sourceLineNo">8677</span>  public void reportCompactionRequestEnd(boolean isMajor, int numFiles, long filesSizeCompacted) {<a name="line.8677"></a>
+<span class="sourceLineNo">8678</span>    int newValue = (isMajor ? majorInProgress : minorInProgress).decrementAndGet();<a name="line.8678"></a>
+<span class="sourceLineNo">8679</span><a name="line.8679"></a>
+<span class="sourceLineNo">8680</span>    // metrics<a name="line.8680"></a>
+<span class="sourceLineNo">8681</span>    compactionsFinished.increment();<a name="line.8681"></a>
+<span class="sourceLineNo">8682</span>    compactionNumFilesCompacted.add(numFiles);<a name="line.8682"></a>
+<span class="sourceLineNo">8683</span>    compactionNumBytesCompacted.add(filesSizeCompacted);<a name="line.8683"></a>
 <span class="sourceLineNo">8684</span><a name="line.8684"></a>
-<span class="sourceLineNo">8685</span>  public void reportCompactionRequestFailure() {<a name="line.8685"></a>
-<span class="sourceLineNo">8686</span>    compactionsFailed.increment();<a name="line.8686"></a>
-<span class="sourceLineNo">8687</span>  }<a name="line.8687"></a>
-<span class="sourceLineNo">8688</span><a name="line.8688"></a>
-<span class="sourceLineNo">8689</span>  public void incrementCompactionsQueuedCount() {<a name="line.8689"></a>
-<span class="sourceLineNo">8690</span>    compactionsQueued.increment();<a name="line.8690"></a>
-<span class="sourceLineNo">8691</span>  }<a name="line.8691"></a>
-<span class="sourceLineNo">8692</span><a name="line.8692"></a>
-<span class="sourceLineNo">8693</span>  public void decrementCompactionsQueuedCount() {<a name="line.8693"></a>
-<span class="sourceLineNo">8694</span>    compactionsQueued.decrement();<a name="line.8694"></a>
-<span class="sourceLineNo">8695</span>  }<a name="line.8695"></a>
-<span class="sourceLineNo">8696</span><a name="line.8696"></a>
-<span class="sourceLineNo">8697</span>  public void incrementFlushesQueuedCount() {<a name="line.8697"></a>
-<span class="sourceLineNo">8698</span>    flushesQueued.increment();<a name="line.8698"></a>
-<span class="sourceLineNo">8699</span>  }<a name="line.8699"></a>
-<span class="sourceLineNo">8700</span><a name="line.8700"></a>
-<span class="sourceLineNo">8701</span>  @VisibleForTesting<a name="line.8701"></a>
-<span class="sourceLineNo">8702</span>  public long getReadPoint() {<a name="line.8702"></a>
-<span class="sourceLineNo">8703</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8703"></a>
-<span class="sourceLineNo">8704</span>  }<a name="line.8704"></a>
-<span class="sourceLineNo">8705</span><a name="line.8705"></a>
-<span class="sourceLineNo">8706</span>  /**<a name="line.8706"></a>
-<span class="sourceLineNo">8707</span>   * {@inheritDoc}<a name="line.8707"></a>
-<span class="sourceLineNo">8708</span>   */<a name="line.8708"></a>
-<span class="sourceLineNo">8709</span>  @Override<a name="line.8709"></a>
-<span class="sourceLineNo">8710</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8710"></a>
-<span class="sourceLineNo">8711</span>    this.storeHotnessProtector.update(conf);<a name="line.8711"></a>
-<span class="sourceLineNo">8712</span>  }<a name="line.8712"></a>
-<span class="sourceLineNo">8713</span><a name="line.8713"></a>
-<span class="sourceLineNo">8714</span>  /**<a name="line.8714"></a>
-<span class="sourceLineNo">8715</span>   * {@inheritDoc}<a name="line.8715"></a>
-<span class="sourceLineNo">8716</span>   */<a name="line.8716"></a>
-<span class="sourceLineNo">8717</span>  @Override<a name="line.8717"></a>
-<span class="sourceLineNo">8718</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8718"></a>
-<span class="sourceLineNo">8719</span>    configurationManager = Optional.of(manager);<a name="line.8719"></a>
-<span class="sourceLineNo">8720</span>    stores.values().forEach(manager::registerObserver);<a name="line.8720"></a>
-<span class="sourceLineNo">8721</span>  }<a name="line.8721"></a>
-<span class="sourceLineNo">8722</span><a name="line.8722"></a>
-<span class="sourceLineNo">8723</span>  /**<a name="line.8723"></a>
-<span class="sourceLineNo">8724</span>   * {@inheritDoc}<a name="line.8724"></a>
-<span class="sourceLineNo">8725</span>   */<a name="line.8725"></a>
-<span class="sourceLineNo">8726</span>  @Override<a name="line.8726"></a>
-<span class="sourceLineNo">8727</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8727"></a>
-<span class="sourceLineNo">8728</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8728"></a>
-<span class="sourceLineNo">8729</span>  }<a name="line.8729"></a>
-<span class="sourceLineNo">8730</span><a name="line.8730"></a>
-<span class="sourceLineNo">8731</span>  @Override<a name="line.8731"></a>
-<span class="sourceLineNo">8732</span>  public CellComparator getCellComparator() {<a name="line.8732"></a>
-<span class="sourceLineNo">8733</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8733"></a>
-<span class="sourceLineNo">8734</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8734"></a>
-<span class="sourceLineNo">8735</span>  }<a name="line.8735"></a>
-<span class="sourceLineNo">8736</span><a name="line.8736"></a>
-<span class="sourceLineNo">8737</span>  public long getMemStoreFlushSize() {<a name="line.8737"></a>
-<span class="sourceLineNo">8738</span>    return this.memstoreFlushSize;<a name="line.8738"></a>
-<span class="sourceLineNo">8739</span>  }<a name="line.8739"></a>
-<span class="sourceLineNo">8740</span><a name="line.8740"></a>
-<span class="sourceLineNo">8741</span><a name="line.8741"></a>
-<span class="sourceLineNo">8742</span>  //// method for debugging tests<a name="line.8742"></a>
-<span class="sourceLineNo">8743</span>  void throwException(String title, String regionName) {<a name="line.8743"></a>
-<span class="sourceLineNo">8744</span>    StringBuilder buf = new StringBuilder();<a name="line.8744"></a>
-<span class="sourceLineNo">8745</span>    buf.append(title + ", ");<a name="line.8745"></a>
-<span class="sourceLineNo">8746</span>    buf.append(getRegionInfo().toString());<a name="line.8746"></a>
-<span class="sourceLineNo">8747</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8747"></a>
-<span class="sourceLineNo">8748</span>    buf.append("stores: ");<a name="line.8748"></a>
-<span class="sourceLineNo">8749</span>    for (HStore s : stores.values()) {<a name="line.8749"></a>
-<span class="sourceLineNo">8750</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8750"></a>
-<span class="sourceLineNo">8751</span>      buf.append(" size: ");<a name="line.8751"></a>
-<span class="sourceLineNo">8752</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8752"></a>
-<span class="sourceLineNo">8753</span>      buf.append(" ");<a name="line.8753"></a>
-<span class="sourceLineNo">8754</span>    }<a name="line.8754"></a>
-<span class="sourceLineNo">8755</span>    buf.append("end-of-stores");<a name="line.8755"></a>
-<span class="sourceLineNo">8756</span>    buf.append(", memstore size ");<a name="line.8756"></a>
-<span class="sourceLineNo">8757</span>    buf.append(getMemStoreDataSize());<a name="line.8757"></a>
-<span class="sourceLineNo">8758</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8758"></a>
-<span class="sourceLineNo">8759</span>      throw new RuntimeException(buf.toString());<a name="line.8759"></a>
-<span class="sourceLineNo">8760</span>    }<a name="line.8760"></a>
-<span class="sourceLineNo">8761</span>  }<a name="line.8761"></a>
-<span class="sourceLineNo">8762</span><a name="line.8762"></a>
-<span class="sourceLineNo">8763</span>  @Override<a name="line.8763"></a>
-<span class="sourceLineNo">8764</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8764"></a>
-<span class="sourceLineNo">8765</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8765"></a>
-<span class="sourceLineNo">8766</span>    if (major) {<a name="line.8766"></a>
-<span class="sourceLineNo">8767</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8767"></a>
-<span class="sourceLineNo">8768</span>    }<a name="line.8768"></a>
-<span class="sourceLineNo">8769</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8769"></a>
-<span class="sourceLineNo">8770</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8770"></a>
-<span class="sourceLineNo">8771</span>  }<a name="line.8771"></a>
-<span class="sourceLineNo">8772</span><a name="line.8772"></a>
-<span class="sourceLineNo">8773</span>  @Override<a name="line.8773"></a>
-<span class="sourceLineNo">8774</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8774"></a>
-<span class="sourceLineNo">8775</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8775"></a>
-<span class="sourceLineNo">8776</span>    HStore store = stores.get(family);<a name="line.8776"></a>
-<span class="sourceLineNo">8777</span>    if (store == null) {<a name="line.8777"></a>
-<span class="sourceLineNo">8778</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8778"></a>
-<span class="sourceLineNo">8779</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8779"></a>
-<span class="sourceLineNo">8780</span>    }<a name="line.8780"></a>
-<span class="sourceLineNo">8781</span>    if (major) {<a name="line.8781"></a>
-<span class="sourceLineNo">8782</span>      store.triggerMajorCompaction();<a name="line.8782"></a>
+<span class="sourceLineNo">8685</span>    assert newValue &gt;= 0;<a name="line.8685"></a>
+<span class="sourceLineNo">8686</span>  }<a name="line.8686"></a>
+<span class="sourceLineNo">8687</span><a name="line.8687"></a>
+<span class="sourceLineNo">8688</span>  public void reportCompactionRequestFailure() {<a name="line.8688"></a>
+<span class="sourceLineNo">8689</span>    compactionsFailed.increment();<a name="line.8689"></a>
+<span class="sourceLineNo">8690</span>  }<a name="line.8690"></a>
+<span class="sourceLineNo">8691</span><a name="line.8691"></a>
+<span class="sourceLineNo">8692</span>  public void incrementCompactionsQueuedCount() {<a name="line.8692"></a>
+<span class="sourceLineNo">8693</span>    compactionsQueued.increment();<a name="line.8693"></a>
+<span class="sourceLineNo">8694</span>  }<a name="line.8694"></a>
+<span class="sourceLineNo">8695</span><a name="line.8695"></a>
+<span class="sourceLineNo">8696</span>  public void decrementCompactionsQueuedCount() {<a name="line.8696"></a>
+<span class="sourceLineNo">8697</span>    compactionsQueued.decrement();<a name="line.8697"></a>
+<span class="sourceLineNo">8698</span>  }<a name="line.8698"></a>
+<span class="sourceLineNo">8699</span><a name="line.8699"></a>
+<span class="sourceLineNo">8700</span>  public void incrementFlushesQueuedCount() {<a name="line.8700"></a>
+<span class="sourceLineNo">8701</span>    flushesQueued.increment();<a name="line.8701"></a>
+<span class="sourceLineNo">8702</span>  }<a name="line.8702"></a>
+<span class="sourceLineNo">8703</span><a name="line.8703"></a>
+<span class="sourceLineNo">8704</span>  @VisibleForTesting<a name="line.8704"></a>
+<span class="sourceLineNo">8705</span>  public long getReadPoint() {<a name="line.8705"></a>
+<span class="sourceLineNo">8706</span>    return getReadPoint(IsolationLevel.READ_COMMITTED);<a name="line.8706"></a>
+<span class="sourceLineNo">8707</span>  }<a name="line.8707"></a>
+<span class="sourceLineNo">8708</span><a name="line.8708"></a>
+<span class="sourceLineNo">8709</span>  /**<a name="line.8709"></a>
+<span class="sourceLineNo">8710</span>   * {@inheritDoc}<a name="line.8710"></a>
+<span class="sourceLineNo">8711</span>   */<a name="line.8711"></a>
+<span class="sourceLineNo">8712</span>  @Override<a name="line.8712"></a>
+<span class="sourceLineNo">8713</span>  public void onConfigurationChange(Configuration conf) {<a name="line.8713"></a>
+<span class="sourceLineNo">8714</span>    this.storeHotnessProtector.update(conf);<a name="line.8714"></a>
+<span class="sourceLineNo">8715</span>  }<a name="line.8715"></a>
+<span class="sourceLineNo">8716</span><a name="line.8716"></a>
+<span class="sourceLineNo">8717</span>  /**<a name="line.8717"></a>
+<span class="sourceLineNo">8718</span>   * {@inheritDoc}<a name="line.8718"></a>
+<span class="sourceLineNo">8719</span>   */<a name="line.8719"></a>
+<span class="sourceLineNo">8720</span>  @Override<a name="line.8720"></a>
+<span class="sourceLineNo">8721</span>  public void registerChildren(ConfigurationManager manager) {<a name="line.8721"></a>
+<span class="sourceLineNo">8722</span>    configurationManager = Optional.of(manager);<a name="line.8722"></a>
+<span class="sourceLineNo">8723</span>    stores.values().forEach(manager::registerObserver);<a name="line.8723"></a>
+<span class="sourceLineNo">8724</span>  }<a name="line.8724"></a>
+<span class="sourceLineNo">8725</span><a name="line.8725"></a>
+<span class="sourceLineNo">8726</span>  /**<a name="line.8726"></a>
+<span class="sourceLineNo">8727</span>   * {@inheritDoc}<a name="line.8727"></a>
+<span class="sourceLineNo">8728</span>   */<a name="line.8728"></a>
+<span class="sourceLineNo">8729</span>  @Override<a name="line.8729"></a>
+<span class="sourceLineNo">8730</span>  public void deregisterChildren(ConfigurationManager manager) {<a name="line.8730"></a>
+<span class="sourceLineNo">8731</span>    stores.values().forEach(configurationManager.get()::deregisterObserver);<a name="line.8731"></a>
+<span class="sourceLineNo">8732</span>  }<a name="line.8732"></a>
+<span class="sourceLineNo">8733</span><a name="line.8733"></a>
+<span class="sourceLineNo">8734</span>  @Override<a name="line.8734"></a>
+<span class="sourceLineNo">8735</span>  public CellComparator getCellComparator() {<a name="line.8735"></a>
+<span class="sourceLineNo">8736</span>    return this.getRegionInfo().isMetaRegion() ? CellComparatorImpl.META_COMPARATOR<a name="line.8736"></a>
+<span class="sourceLineNo">8737</span>        : CellComparatorImpl.COMPARATOR;<a name="line.8737"></a>
+<span class="sourceLineNo">8738</span>  }<a name="line.8738"></a>
+<span class="sourceLineNo">8739</span><a name="line.8739"></a>
+<span class="sourceLineNo">8740</span>  public long getMemStoreFlushSize() {<a name="line.8740"></a>
+<span class="sourceLineNo">8741</span>    return this.memstoreFlushSize;<a name="line.8741"></a>
+<span class="sourceLineNo">8742</span>  }<a name="line.8742"></a>
+<span class="sourceLineNo">8743</span><a name="line.8743"></a>
+<span class="sourceLineNo">8744</span><a name="line.8744"></a>
+<span class="sourceLineNo">8745</span>  //// method for debugging tests<a name="line.8745"></a>
+<span class="sourceLineNo">8746</span>  void throwException(String title, String regionName) {<a name="line.8746"></a>
+<span class="sourceLineNo">8747</span>    StringBuilder buf = new StringBuilder();<a name="line.8747"></a>
+<span class="sourceLineNo">8748</span>    buf.append(title + ", ");<a name="line.8748"></a>
+<span class="sourceLineNo">8749</span>    buf.append(getRegionInfo().toString());<a name="line.8749"></a>
+<span class="sourceLineNo">8750</span>    buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");<a name="line.8750"></a>
+<span class="sourceLineNo">8751</span>    buf.append("stores: ");<a name="line.8751"></a>
+<span class="sourceLineNo">8752</span>    for (HStore s : stores.values()) {<a name="line.8752"></a>
+<span class="sourceLineNo">8753</span>      buf.append(s.getColumnFamilyDescriptor().getNameAsString());<a name="line.8753"></a>
+<span class="sourceLineNo">8754</span>      buf.append(" size: ");<a name="line.8754"></a>
+<span class="sourceLineNo">8755</span>      buf.append(s.getMemStoreSize().getDataSize());<a name="line.8755"></a>
+<span class="sourceLineNo">8756</span>      buf.append(" ");<a name="line.8756"></a>
+<span class="sourceLineNo">8757</span>    }<a name="line.8757"></a>
+<span class="sourceLineNo">8758</span>    buf.append("end-of-stores");<a name="line.8758"></a>
+<span class="sourceLineNo">8759</span>    buf.append(", memstore size ");<a name="line.8759"></a>
+<span class="sourceLineNo">8760</span>    buf.append(getMemStoreDataSize());<a name="line.8760"></a>
+<span class="sourceLineNo">8761</span>    if (getRegionInfo().getRegionNameAsString().startsWith(regionName)) {<a name="line.8761"></a>
+<span class="sourceLineNo">8762</span>      throw new RuntimeException(buf.toString());<a name="line.8762"></a>
+<span class="sourceLineNo">8763</span>    }<a name="line.8763"></a>
+<span class="sourceLineNo">8764</span>  }<a name="line.8764"></a>
+<span class="sourceLineNo">8765</span><a name="line.8765"></a>
+<span class="sourceLineNo">8766</span>  @Override<a name="line.8766"></a>
+<span class="sourceLineNo">8767</span>  public void requestCompaction(String why, int priority, boolean major,<a name="line.8767"></a>
+<span class="sourceLineNo">8768</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8768"></a>
+<span class="sourceLineNo">8769</span>    if (major) {<a name="line.8769"></a>
+<span class="sourceLineNo">8770</span>      stores.values().forEach(HStore::triggerMajorCompaction);<a name="line.8770"></a>
+<span class="sourceLineNo">8771</span>    }<a name="line.8771"></a>
+<span class="sourceLineNo">8772</span>    rsServices.getCompactionRequestor().requestCompaction(this, why, priority, tracker,<a name="line.8772"></a>
+<span class="sourceLineNo">8773</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8773"></a>
+<span class="sourceLineNo">8774</span>  }<a name="line.8774"></a>
+<span class="sourceLineNo">8775</span><a name="line.8775"></a>
+<span class="sourceLineNo">8776</span>  @Override<a name="line.8776"></a>
+<span class="sourceLineNo">8777</span>  public void requestCompaction(byte[] family, String why, int priority, boolean major,<a name="line.8777"></a>
+<span class="sourceLineNo">8778</span>      CompactionLifeCycleTracker tracker) throws IOException {<a name="line.8778"></a>
+<span class="sourceLineNo">8779</span>    HStore store = stores.get(family);<a name="line.8779"></a>
+<span class="sourceLineNo">8780</span>    if (store == null) {<a name="line.8780"></a>
+<span class="sourceLineNo">8781</span>      throw new NoSuchColumnFamilyException("column family " + Bytes.toString(family) +<a name="line.8781"></a>
+<span class="sourceLineNo">8782</span>          " does not exist in region " + getRegionInfo().getRegionNameAsString());<a name="line.8782"></a>
 <span class="sourceLineNo">8783</span>    }<a name="line.8783"></a>
-<span class="sourceLineNo">8784</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8784"></a>
-<span class="sourceLineNo">8785</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8785"></a>
-<span class="sourceLineNo">8786</span>  }<a name="line.8786"></a>
-<span class="sourceLineNo">8787</span><a name="line.8787"></a>
-<span class="sourceLineNo">8788</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8788"></a>
-<span class="sourceLineNo">8789</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8789"></a>
-<span class="sourceLineNo">8790</span>      requestFlush();<a name="line.8790"></a>
-<span class="sourceLineNo">8791</span>    }<a name="line.8791"></a>
-<span class="sourceLineNo">8792</span>  }<a name="line.8792"></a>
-<span class="sourceLineNo">8793</span><a name="line.8793"></a>
-<span class="sourceLineNo">8794</span>  private void requestFlush() {<a name="line.8794"></a>
-<span class="sourceLineNo">8795</span>    if (this.rsServices == null) {<a name="line.8795"></a>
-<span class="sourceLineNo">8796</span>      return;<a name="line.8796"></a>
-<span class="sourceLineNo">8797</span>    }<a name="line.8797"></a>
-<span class="sourceLineNo">8798</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8798"></a>
-<span class="sourceLineNo">8799</span>  }<a name="line.8799"></a>
-<span class="sourceLineNo">8800</span><a name="line.8800"></a>
-<span class="sourceLineNo">8801</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8801"></a>
-<span class="sourceLineNo">8802</span>    boolean shouldFlush = false;<a name="line.8802"></a>
-<span class="sourceLineNo">8803</span>    synchronized (writestate) {<a name="line.8803"></a>
-<span class="sourceLineNo">8804</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8804"></a>
-<span class="sourceLineNo">8805</span>        shouldFlush = true;<a name="line.8805"></a>
-<span class="sourceLineNo">8806</span>        writestate.flushRequested = true;<a name="line.8806"></a>
-<span class="sourceLineNo">8807</span>      }<a name="line.8807"></a>
-<span class="sourceLineNo">8808</span>    }<a name="line.8808"></a>
-<span class="sourceLineNo">8809</span>    if (shouldFlush) {<a name="line.8809"></a>
-<span class="sourceLineNo">8810</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8810"></a>
-<span class="sourceLineNo">8811</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8811"></a>
-<span class="sourceLineNo">8812</span>      if (LOG.isDebugEnabled()) {<a name="line.8812"></a>
-<span class="sourceLineNo">8813</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8813"></a>
-<span class="sourceLineNo">8814</span>      }<a name="line.8814"></a>
-<span class="sourceLineNo">8815</span>    } else {<a name="line.8815"></a>
-<span class="sourceLineNo">8816</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8816"></a>
-<span class="sourceLineNo">8817</span>    }<a name="line.8817"></a>
-<span class="sourceLineNo">8818</span>  }<a name="line.8818"></a>
-<span class="sourceLineNo">8819</span><a name="line.8819"></a>
-<span class="sourceLineNo">8820</span>  @Override<a name="line.8820"></a>
-<span class="sourceLineNo">8821</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8821"></a>
-<span class="sourceLineNo">8822</span>    requestFlush0(tracker);<a name="line.8822"></a>
-<span class="sourceLineNo">8823</span>  }<a name="line.8823"></a>
-<span class="sourceLineNo">8824</span><a name="line.8824"></a>
-<span class="sourceLineNo">8825</span>  /**<a name="line.8825"></a>
-<span class="sourceLineNo">8826</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8826"></a>
-<span class="sourceLineNo">8827</span>   * features<a name="line.8827"></a>
-<span class="sourceLineNo">8828</span>   * @param conf region configurations<a name="line.8828"></a>
-<span class="sourceLineNo">8829</span>   */<a name="line.8829"></a>
-<span class="sourceLineNo">8830</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8830"></a>
-<span class="sourceLineNo">8831</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8831"></a>
-<span class="sourceLineNo">8832</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8832"></a>
-<span class="sourceLineNo">8833</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8833"></a>
-<span class="sourceLineNo">8834</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8834"></a>
-<span class="sourceLineNo">8835</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8835"></a>
-<span class="sourceLineNo">8836</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8836"></a>
-<span class="sourceLineNo">8837</span>      }<a name="line.8837"></a>
-<span class="sourceLineNo">8838</span>    }<a name="line.8838"></a>
-<span class="sourceLineNo">8839</span>  }<a name="line.8839"></a>
-<span class="sourceLineNo">8840</span>}<a name="line.8840"></a>
+<span class="sourceLineNo">8784</span>    if (major) {<a name="line.8784"></a>
+<span class="sourceLineNo">8785</span>      store.triggerMajorCompaction();<a name="line.8785"></a>
+<span class="sourceLineNo">8786</span>    }<a name="line.8786"></a>
+<span class="sourceLineNo">8787</span>    rsServices.getCompactionRequestor().requestCompaction(this, store, why, priority, tracker,<a name="line.8787"></a>
+<span class="sourceLineNo">8788</span>        RpcServer.getRequestUser().orElse(null));<a name="line.8788"></a>
+<span class="sourceLineNo">8789</span>  }<a name="line.8789"></a>
+<span class="sourceLineNo">8790</span><a name="line.8790"></a>
+<span class="sourceLineNo">8791</span>  private void requestFlushIfNeeded() throws RegionTooBusyException {<a name="line.8791"></a>
+<span class="sourceLineNo">8792</span>    if(isFlushSize(this.memStoreSizing.getMemStoreSize())) {<a name="line.8792"></a>
+<span class="sourceLineNo">8793</span>      requestFlush();<a name="line.8793"></a>
+<span class="sourceLineNo">8794</span>    }<a name="line.8794"></a>
+<span class="sourceLineNo">8795</span>  }<a name="line.8795"></a>
+<span class="sourceLineNo">8796</span><a name="line.8796"></a>
+<span class="sourceLineNo">8797</span>  private void requestFlush() {<a name="line.8797"></a>
+<span class="sourceLineNo">8798</span>    if (this.rsServices == null) {<a name="line.8798"></a>
+<span class="sourceLineNo">8799</span>      return;<a name="line.8799"></a>
+<span class="sourceLineNo">8800</span>    }<a name="line.8800"></a>
+<span class="sourceLineNo">8801</span>    requestFlush0(FlushLifeCycleTracker.DUMMY);<a name="line.8801"></a>
+<span class="sourceLineNo">8802</span>  }<a name="line.8802"></a>
+<span class="sourceLineNo">8803</span><a name="line.8803"></a>
+<span class="sourceLineNo">8804</span>  private void requestFlush0(FlushLifeCycleTracker tracker) {<a name="line.8804"></a>
+<span class="sourceLineNo">8805</span>    boolean shouldFlush = false;<a name="line.8805"></a>
+<span class="sourceLineNo">8806</span>    synchronized (writestate) {<a name="line.8806"></a>
+<span class="sourceLineNo">8807</span>      if (!this.writestate.isFlushRequested()) {<a name="line.8807"></a>
+<span class="sourceLineNo">8808</span>        shouldFlush = true;<a name="line.8808"></a>
+<span class="sourceLineNo">8809</span>        writestate.flushRequested = true;<a name="line.8809"></a>
+<span class="sourceLineNo">8810</span>      }<a name="line.8810"></a>
+<span class="sourceLineNo">8811</span>    }<a name="line.8811"></a>
+<span class="sourceLineNo">8812</span>    if (shouldFlush) {<a name="line.8812"></a>
+<span class="sourceLineNo">8813</span>      // Make request outside of synchronize block; HBASE-818.<a name="line.8813"></a>
+<span class="sourceLineNo">8814</span>      this.rsServices.getFlushRequester().requestFlush(this, false, tracker);<a name="line.8814"></a>
+<span class="sourceLineNo">8815</span>      if (LOG.isDebugEnabled()) {<a name="line.8815"></a>
+<span class="sourceLineNo">8816</span>        LOG.debug("Flush requested on " + this.getRegionInfo().getEncodedName());<a name="line.8816"></a>
+<span class="sourceLineNo">8817</span>      }<a name="line.8817"></a>
+<span class="sourceLineNo">8818</span>    } else {<a name="line.8818"></a>
+<span class="sourceLineNo">8819</span>      tracker.notExecuted("Flush already requested on " + this);<a name="line.8819"></a>
+<span class="sourceLineNo">8820</span>    }<a name="line.8820"></a>
+<span class="sourceLineNo">8821</span>  }<a name="line.8821"></a>
+<span class="sourceLineNo">8822</span><a name="line.8822"></a>
+<span class="sourceLineNo">8823</span>  @Override<a name="line.8823"></a>
+<span class="sourceLineNo">8824</span>  public void requestFlush(FlushLifeCycleTracker tracker) throws IOException {<a name="line.8824"></a>
+<span class="sourceLineNo">8825</span>    requestFlush0(tracker);<a name="line.8825"></a>
+<span class="sourceLineNo">8826</span>  }<a name="line.8826"></a>
+<span class="sourceLineNo">8827</span><a name="line.8827"></a>
+<span class="sourceLineNo">8828</span>  /**<a name="line.8828"></a>
+<span class="sourceLineNo">8829</span>   * This method modifies the region's configuration in order to inject replication-related<a name="line.8829"></a>
+<span class="sourceLineNo">8830</span>   * features<a name="line.8830"></a>
+<span class="sourceLineNo">8831</span>   * @param conf region configurations<a name="line.8831"></a>
+<span class="sourceLineNo">8832</span>   */<a name="line.8832"></a>
+<span class="sourceLineNo">8833</span>  static void decorateRegionConfiguration(Configuration conf) {<a name="line.8833"></a>
+<span class="sourceLineNo">8834</span>    if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {<a name="line.8834"></a>
+<span class="sourceLineNo">8835</span>      String plugins = conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,"");<a name="line.8835"></a>
+<span class="sourceLineNo">8836</span>      String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName();<a name="line.8836"></a>
+<span class="sourceLineNo">8837</span>      if (!plugins.contains(replicationCoprocessorClass)) {<a name="line.8837"></a>
+<span class="sourceLineNo">8838</span>        conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,<a name="line.8838"></a>
+<span class="sourceLineNo">8839</span>            (plugins.equals("") ? "" : (plugins + ",")) + replicationCoprocessorClass);<a name="line.8839"></a>
+<span class="sourceLineNo">8840</span>      }<a name="line.8840"></a>
+<span class="sourceLineNo">8841</span>    }<a name="line.8841"></a>
+<span class="sourceLineNo">8842</span>  }<a name="line.8842"></a>
+<span class="sourceLineNo">8843</span>}<a name="line.8843"></a>
 
 
 
diff --git a/downloads.html b/downloads.html
index a9b8fd8..dfb522f 100644
--- a/downloads.html
+++ b/downloads.html
@@ -394,7 +394,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/export_control.html b/export_control.html
index 0aaa184..0cdd256 100644
--- a/export_control.html
+++ b/export_control.html
@@ -180,7 +180,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/index.html b/index.html
index 0ca95e9..03f2158 100644
--- a/index.html
+++ b/index.html
@@ -258,7 +258,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/issue-tracking.html b/issue-tracking.html
index ad31c91..abc3ed3 100644
--- a/issue-tracking.html
+++ b/issue-tracking.html
@@ -152,7 +152,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/mail-lists.html b/mail-lists.html
index ed44813..e0b60a0 100644
--- a/mail-lists.html
+++ b/mail-lists.html
@@ -205,7 +205,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/metrics.html b/metrics.html
index fa5904a..e8c1ade 100644
--- a/metrics.html
+++ b/metrics.html
@@ -308,7 +308,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/old_news.html b/old_news.html
index d2bf9a7..8fa268f 100644
--- a/old_news.html
+++ b/old_news.html
@@ -299,7 +299,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/plugin-management.html b/plugin-management.html
index 6493c04..58bf82c 100644
--- a/plugin-management.html
+++ b/plugin-management.html
@@ -304,7 +304,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/plugins.html b/plugins.html
index 739e39c..c3b8b34 100644
--- a/plugins.html
+++ b/plugins.html
@@ -231,7 +231,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/poweredbyhbase.html b/poweredbyhbase.html
index 48be349..c5e7591 100644
--- a/poweredbyhbase.html
+++ b/poweredbyhbase.html
@@ -618,7 +618,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/project-info.html b/project-info.html
index e4fa998..1e2aa82 100644
--- a/project-info.html
+++ b/project-info.html
@@ -193,7 +193,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/project-reports.html b/project-reports.html
index 1a13c75..db56ee8 100644
--- a/project-reports.html
+++ b/project-reports.html
@@ -169,7 +169,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/project-summary.html b/project-summary.html
index 0e3813e..69ddab2 100644
--- a/project-summary.html
+++ b/project-summary.html
@@ -195,7 +195,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/pseudo-distributed.html b/pseudo-distributed.html
index bd65a0f..961c2c6 100644
--- a/pseudo-distributed.html
+++ b/pseudo-distributed.html
@@ -157,7 +157,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/replication.html b/replication.html
index 8603e1a..305dfd8 100644
--- a/replication.html
+++ b/replication.html
@@ -152,7 +152,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/resources.html b/resources.html
index d409e8f..a17e79c 100644
--- a/resources.html
+++ b/resources.html
@@ -180,7 +180,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/source-repository.html b/source-repository.html
index d8d3e9b..722f0d1 100644
--- a/source-repository.html
+++ b/source-repository.html
@@ -163,7 +163,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/sponsors.html b/sponsors.html
index 753456c..32f86d7 100644
--- a/sponsors.html
+++ b/sponsors.html
@@ -182,7 +182,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/supportingprojects.html b/supportingprojects.html
index f90297b..9b567b7 100644
--- a/supportingprojects.html
+++ b/supportingprojects.html
@@ -369,7 +369,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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/team-list.html b/team-list.html
index 322bfa8..2a93590 100644
--- a/team-list.html
+++ b/team-list.html
@@ -666,7 +666,7 @@
         <div class="row">
             <p>Copyright &copy;2007&#x2013;2019
 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
-All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-13</li>
+All rights reserved.        <li id="publishDate" class="pull-right">Last Published: 2019-08-14</li>
 </p>
         </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>